Subversion Repositories shark

Rev

Rev 57 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
57 pj 1
/* $Id: s_readpix.c,v 1.1 2003-02-28 11:49:42 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
 
28
#include "glheader.h"
29
#include "colormac.h"
30
#include "convolve.h"
31
#include "context.h"
32
#include "feedback.h"
33
#include "image.h"
34
#include "macros.h"
35
#include "imports.h"
36
#include "pixel.h"
37
 
38
#include "s_alphabuf.h"
39
#include "s_context.h"
40
#include "s_depth.h"
41
#include "s_span.h"
42
#include "s_stencil.h"
43
 
44
 
45
 
46
/*
47
 * Read a block of color index pixels.
48
 */
49
static void
50
read_index_pixels( GLcontext *ctx,
51
                   GLint x, GLint y,
52
                   GLsizei width, GLsizei height,
53
                   GLenum type, GLvoid *pixels,
54
                   const struct gl_pixelstore_attrib *packing )
55
{
56
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
57
   GLint i, readWidth;
58
 
59
   /* error checking */
60
   if (ctx->Visual.rgbMode) {
61
      _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
62
      return;
63
   }
64
 
65
   _swrast_use_read_buffer(ctx);
66
 
67
   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
68
 
69
   /* process image row by row */
70
   for (i = 0; i < height; i++) {
71
      GLuint index[MAX_WIDTH];
72
      GLvoid *dest;
73
 
74
      (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y + i, index);
75
 
76
      dest = _mesa_image_address(packing, pixels, width, height,
77
                                 GL_COLOR_INDEX, type, 0, i, 0);
78
 
79
      _mesa_pack_index_span(ctx, readWidth, type, dest, index,
80
                            &ctx->Pack, ctx->_ImageTransferState);
81
   }
82
 
83
   _swrast_use_draw_buffer(ctx);
84
}
85
 
86
 
87
 
88
static void
89
read_depth_pixels( GLcontext *ctx,
90
                   GLint x, GLint y,
91
                   GLsizei width, GLsizei height,
92
                   GLenum type, GLvoid *pixels,
93
                   const struct gl_pixelstore_attrib *packing )
94
{
95
   GLint readWidth;
96
   GLboolean bias_or_scale;
97
 
98
   /* Error checking */
99
   if (ctx->Visual.depthBits <= 0) {
100
      /* No depth buffer */
101
      _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
102
      return;
103
   }
104
 
105
   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
106
 
107
   if (type != GL_BYTE &&
108
       type != GL_UNSIGNED_BYTE &&
109
       type != GL_SHORT &&
110
       type != GL_UNSIGNED_SHORT &&
111
       type != GL_INT &&
112
       type != GL_UNSIGNED_INT &&
113
       type != GL_FLOAT) {
114
      _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
115
      return;
116
   }
117
 
118
   bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
119
 
120
   if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
121
       && !bias_or_scale && !packing->SwapBytes) {
122
      /* Special case: directly read 16-bit unsigned depth values. */
123
      GLint j;
124
      for (j=0;j<height;j++,y++) {
125
         GLdepth depth[MAX_WIDTH];
126
         GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
127
                         width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
128
         GLint i;
129
         _mesa_read_depth_span(ctx, width, x, y, depth);
130
         for (i = 0; i < width; i++)
131
            dst[i] = depth[i];
132
      }
133
   }
134
   else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
135
            && !bias_or_scale && !packing->SwapBytes) {
136
      /* Special case: directly read 32-bit unsigned depth values. */
137
      GLint j;
138
      for (j=0;j<height;j++,y++) {
139
         GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
140
                         width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
141
         _mesa_read_depth_span(ctx, width, x, y, dst);
142
      }
143
   }
144
   else {
145
      /* General case (slower) */
146
      GLint j;
147
      for (j=0;j<height;j++,y++) {
148
         GLfloat depth[MAX_WIDTH];
149
         GLvoid *dest;
150
 
151
         _mesa_read_depth_span_float(ctx, readWidth, x, y, depth);
152
 
153
         dest = _mesa_image_address(packing, pixels, width, height,
154
                                    GL_DEPTH_COMPONENT, type, 0, j, 0);
155
 
156
         _mesa_pack_depth_span(ctx, readWidth, (GLdepth *) dest, type,
157
                               depth, &ctx->Pack);
158
      }
159
   }
160
}
161
 
162
 
163
 
164
static void
165
read_stencil_pixels( GLcontext *ctx,
166
                     GLint x, GLint y,
167
                     GLsizei width, GLsizei height,
168
                     GLenum type, GLvoid *pixels,
169
                     const struct gl_pixelstore_attrib *packing )
170
{
171
   GLint j, readWidth;
172
 
173
   if (type != GL_BYTE &&
174
       type != GL_UNSIGNED_BYTE &&
175
       type != GL_SHORT &&
176
       type != GL_UNSIGNED_SHORT &&
177
       type != GL_INT &&
178
       type != GL_UNSIGNED_INT &&
179
       type != GL_FLOAT &&
180
       type != GL_BITMAP) {
181
      _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
182
      return;
183
   }
184
 
185
   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
186
 
187
   if (ctx->Visual.stencilBits <= 0) {
188
      /* No stencil buffer */
189
      _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
190
      return;
191
   }
192
 
193
   /* process image row by row */
194
   for (j=0;j<height;j++,y++) {
195
      GLvoid *dest;
196
      GLstencil stencil[MAX_WIDTH];
197
 
198
      _mesa_read_stencil_span(ctx, readWidth, x, y, stencil);
199
 
200
      dest = _mesa_image_address(packing, pixels, width, height,
201
                                 GL_STENCIL_INDEX, type, 0, j, 0);
202
 
203
      _mesa_pack_stencil_span(ctx, readWidth, type, dest, stencil, &ctx->Pack);
204
   }
205
}
206
 
207
 
208
 
209
/*
210
 * Optimized glReadPixels for particular pixel formats:
211
 *   GL_UNSIGNED_BYTE, GL_RGBA
212
 * when pixel scaling, biasing and mapping are disabled.
213
 */
214
static GLboolean
215
read_fast_rgba_pixels( GLcontext *ctx,
216
                       GLint x, GLint y,
217
                       GLsizei width, GLsizei height,
218
                       GLenum format, GLenum type,
219
                       GLvoid *pixels,
220
                       const struct gl_pixelstore_attrib *packing )
221
{
222
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
223
   /* can't do scale, bias, mapping, etc */
224
   if (ctx->_ImageTransferState)
225
       return GL_FALSE;
226
 
227
   /* can't do fancy pixel packing */
228
   if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
229
      return GL_FALSE;
230
 
231
   {
232
      GLint srcX = x;
233
      GLint srcY = y;
234
      GLint readWidth = width;           /* actual width read */
235
      GLint readHeight = height;         /* actual height read */
236
      GLint skipPixels = packing->SkipPixels;
237
      GLint skipRows = packing->SkipRows;
238
      GLint rowLength;
239
 
240
      if (packing->RowLength > 0)
241
         rowLength = packing->RowLength;
242
      else
243
         rowLength = width;
244
 
245
      /* horizontal clipping */
246
      if (srcX < 0) {
247
         skipPixels -= srcX;
248
         readWidth += srcX;
249
         srcX = 0;
250
      }
251
      if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
252
         readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
253
      if (readWidth <= 0)
254
         return GL_TRUE;
255
 
256
      /* vertical clipping */
257
      if (srcY < 0) {
258
         skipRows -= srcY;
259
         readHeight += srcY;
260
         srcY = 0;
261
      }
262
      if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
263
         readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
264
      if (readHeight <= 0)
265
         return GL_TRUE;
266
 
267
      /*
268
       * Ready to read!
269
       * The window region at (destX, destY) of size (readWidth, readHeight)
270
       * will be read back.
271
       * We'll write pixel data to buffer pointed to by "pixels" but we'll
272
       * skip "skipRows" rows and skip "skipPixels" pixels/row.
273
       */
274
#if CHAN_BITS == 8
275
      if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
276
#elif CHAN_BITS == 16
277
      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
278
#else
279
      if (0) {
280
#endif
281
         GLchan *dest = (GLchan *) pixels
282
                      + (skipRows * rowLength + skipPixels) * 4;
283
         GLint row;
284
 
285
         if (packing->Invert) {
286
            /* start at top and go down */
287
            dest += (readHeight - 1) * rowLength * 4;
288
            rowLength = -rowLength;
289
         }
290
 
291
         for (row=0; row<readHeight; row++) {
292
            (*swrast->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
293
                                        (GLchan (*)[4]) dest);
294
            if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
295
               _mesa_read_alpha_span(ctx, readWidth, srcX, srcY,
296
                                     (GLchan (*)[4]) dest);
297
            }
298
            dest += rowLength * 4;
299
            srcY++;
300
         }
301
         return GL_TRUE;
302
      }
303
      else {
304
         /* can't do this format/type combination */
305
         return GL_FALSE;
306
      }
307
   }
308
}
309
 
310
 
311
 
312
/*
313
 * Read R, G, B, A, RGB, L, or LA pixels.
314
 */
315
static void
316
read_rgba_pixels( GLcontext *ctx,
317
                  GLint x, GLint y,
318
                  GLsizei width, GLsizei height,
319
                  GLenum format, GLenum type, GLvoid *pixels,
320
                  const struct gl_pixelstore_attrib *packing )
321
{
322
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
323
   GLint readWidth;
324
 
325
   _swrast_use_read_buffer(ctx);
326
 
327
   /* Try optimized path first */
328
   if (read_fast_rgba_pixels( ctx, x, y, width, height,
329
                              format, type, pixels, packing )) {
330
 
331
      _swrast_use_draw_buffer(ctx);
332
      return; /* done! */
333
   }
334
 
335
   readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
336
 
337
   /* do error checking on pixel type, format was already checked by caller */
338
   switch (type) {
339
      case GL_UNSIGNED_BYTE:
340
      case GL_BYTE:
341
      case GL_UNSIGNED_SHORT:
342
      case GL_SHORT:
343
      case GL_UNSIGNED_INT:
344
      case GL_INT:
345
      case GL_FLOAT:
346
      case GL_UNSIGNED_BYTE_3_3_2:
347
      case GL_UNSIGNED_BYTE_2_3_3_REV:
348
      case GL_UNSIGNED_SHORT_5_6_5:
349
      case GL_UNSIGNED_SHORT_5_6_5_REV:
350
      case GL_UNSIGNED_SHORT_4_4_4_4:
351
      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
352
      case GL_UNSIGNED_SHORT_5_5_5_1:
353
      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
354
      case GL_UNSIGNED_INT_8_8_8_8:
355
      case GL_UNSIGNED_INT_8_8_8_8_REV:
356
      case GL_UNSIGNED_INT_10_10_10_2:
357
      case GL_UNSIGNED_INT_2_10_10_10_REV:
358
         /* valid pixel type */
359
         break;
360
      default:
361
         _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
362
         return;
363
   }
364
 
365
   if (!_mesa_is_legal_format_and_type(format, type) ||
366
       format == GL_INTENSITY) {
367
      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
368
      return;
369
   }
370
 
371
   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
372
      const GLuint transferOps = ctx->_ImageTransferState;
373
      GLfloat *dest, *src, *tmpImage, *convImage;
374
      GLint row;
375
 
376
      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
377
      if (!tmpImage) {
378
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
379
         return;
380
      }
381
      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
382
      if (!convImage) {
383
         FREE(tmpImage);
384
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
385
         return;
386
      }
387
 
388
      /* read full RGBA, FLOAT image */
389
      dest = tmpImage;
390
      for (row = 0; row < height; row++, y++) {
391
         GLchan rgba[MAX_WIDTH][4];
392
         if (ctx->Visual.rgbMode) {
393
            _mesa_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
394
         }
395
         else {
396
            GLuint index[MAX_WIDTH];
397
            (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
398
            if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
399
               _mesa_map_ci(ctx, readWidth, index);
400
            }
401
            _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
402
         }
403
         _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
404
                              GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
405
                              transferOps & IMAGE_PRE_CONVOLUTION_BITS);
406
         dest += width * 4;
407
      }
408
 
409
      /* do convolution */
410
      if (ctx->Pixel.Convolution2DEnabled) {
411
         _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
412
      }
413
      else {
414
         ASSERT(ctx->Pixel.Separable2DEnabled);
415
         _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
416
      }
417
      FREE(tmpImage);
418
 
419
      /* finish transfer ops and pack the resulting image */
420
      src = convImage;
421
      for (row = 0; row < height; row++) {
422
         GLvoid *dest;
423
         dest = _mesa_image_address(packing, pixels, readWidth, height,
424
                                    format, type, 0, row, 0);
425
         _mesa_pack_float_rgba_span(ctx, readWidth,
426
                                    (const GLfloat (*)[4]) src,
427
                                    format, type, dest, packing,
428
                                    transferOps & IMAGE_POST_CONVOLUTION_BITS);
429
         src += readWidth * 4;
430
      }
431
   }
432
   else {
433
      /* no convolution */
434
      GLint row;
435
      for (row = 0; row < height; row++, y++) {
436
         GLchan rgba[MAX_WIDTH][4];
437
         GLvoid *dst;
438
         if (ctx->Visual.rgbMode) {
439
            _mesa_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
440
         }
441
         else {
442
            GLuint index[MAX_WIDTH];
443
            (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
444
            if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
445
               _mesa_map_ci(ctx, readWidth, index);
446
            }
447
            _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
448
         }
449
         dst = _mesa_image_address(packing, pixels, width, height,
450
                                   format, type, 0, row, 0);
451
         if (ctx->Visual.redBits < CHAN_BITS ||
452
             ctx->Visual.greenBits < CHAN_BITS ||
453
             ctx->Visual.blueBits < CHAN_BITS) {
454
            /* Requantize the color values into floating point and go from
455
             * there.  This fixes conformance failures with 16-bit color
456
             * buffers, for example.
457
             */
458
            DEFMARRAY(GLfloat, rgbaf, MAX_WIDTH, 4);  /* mac 32k limitation */
459
            CHECKARRAY(rgbaf, return);  /* mac 32k limitation */
460
            _mesa_chan_to_float_span(ctx, readWidth,
461
                                     (CONST GLchan (*)[4]) rgba, rgbaf);
462
            _mesa_pack_float_rgba_span(ctx, readWidth,
463
                                       (CONST GLfloat (*)[4]) rgbaf,
464
                                       format, type, dst, packing,
465
                                       ctx->_ImageTransferState);
466
            UNDEFARRAY(rgbaf);  /* mac 32k limitation */
467
         }
468
         else {
469
            /* GLubytes are fine */
470
            _mesa_pack_rgba_span(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
471
                                 format, type, dst, packing,
472
                                 ctx->_ImageTransferState);
473
         }
474
      }
475
   }
476
 
477
   _swrast_use_draw_buffer(ctx);
478
}
479
 
480
 
481
 
482
void
483
_swrast_ReadPixels( GLcontext *ctx,
484
                    GLint x, GLint y, GLsizei width, GLsizei height,
485
                    GLenum format, GLenum type,
486
                    const struct gl_pixelstore_attrib *pack,
487
                    GLvoid *pixels )
488
{
489
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
490
   (void) pack;
491
 
492
   if (swrast->NewState)
493
      _swrast_validate_derived( ctx );
494
 
495
   RENDER_START(swrast,ctx);
496
 
497
   switch (format) {
498
      case GL_COLOR_INDEX:
499
         read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
500
         break;
501
      case GL_STENCIL_INDEX:
502
         read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
503
         break;
504
      case GL_DEPTH_COMPONENT:
505
         read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
506
         break;
507
      case GL_RED:
508
      case GL_GREEN:
509
      case GL_BLUE:
510
      case GL_ALPHA:
511
      case GL_RGB:
512
      case GL_LUMINANCE:
513
      case GL_LUMINANCE_ALPHA:
514
      case GL_RGBA:
515
      case GL_BGR:
516
      case GL_BGRA:
517
      case GL_ABGR_EXT:
518
         read_rgba_pixels(ctx, x, y, width, height,
519
                          format, type, pixels, &ctx->Pack);
520
         break;
521
      default:
522
         _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
523
   }
524
 
525
   RENDER_FINISH(swrast,ctx);
526
}