s_drawpix.c revision 2d5b86be25a7ccb729e746aa5e1bdd537d76df68
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "main/glheader.h"
27#include "main/bufferobj.h"
28#include "main/context.h"
29#include "main/convolve.h"
30#include "main/image.h"
31#include "main/macros.h"
32#include "main/imports.h"
33#include "main/pixel.h"
34#include "main/state.h"
35
36#include "s_context.h"
37#include "s_span.h"
38#include "s_stencil.h"
39#include "s_zoom.h"
40
41
42
43/**
44 * Try to do a fast and simple RGB(a) glDrawPixels.
45 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
46 */
47static GLboolean
48fast_draw_rgba_pixels(GLcontext *ctx, GLint x, GLint y,
49                      GLsizei width, GLsizei height,
50                      GLenum format, GLenum type,
51                      const struct gl_pixelstore_attrib *userUnpack,
52                      const GLvoid *pixels)
53{
54   const GLint imgX = x, imgY = y;
55   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
56   GLenum rbType;
57   SWcontext *swrast = SWRAST_CONTEXT(ctx);
58   SWspan span;
59   GLboolean simpleZoom;
60   GLint yStep;  /* +1 or -1 */
61   struct gl_pixelstore_attrib unpack;
62   GLint destX, destY, drawWidth, drawHeight; /* post clipping */
63
64   if (!rb)
65      return GL_TRUE; /* no-op */
66
67   rbType = rb->DataType;
68
69   if ((swrast->_RasterMask & ~CLIP_BIT) ||
70       ctx->Texture._EnabledCoordUnits ||
71       userUnpack->SwapBytes ||
72       ctx->_ImageTransferState) {
73      /* can't handle any of those conditions */
74      return GL_FALSE;
75   }
76
77   INIT_SPAN(span, GL_BITMAP);
78   span.arrayMask = SPAN_RGBA;
79   span.arrayAttribs = FRAG_BIT_COL0;
80   _swrast_span_default_attribs(ctx, &span);
81
82   /* copy input params since clipping may change them */
83   unpack = *userUnpack;
84   destX = x;
85   destY = y;
86   drawWidth = width;
87   drawHeight = height;
88
89   /* check for simple zooming and clipping */
90   if (ctx->Pixel.ZoomX == 1.0F &&
91       (ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F)) {
92      if (!_mesa_clip_drawpixels(ctx, &destX, &destY,
93                                 &drawWidth, &drawHeight, &unpack)) {
94         /* image was completely clipped: no-op, all done */
95         return GL_TRUE;
96      }
97      simpleZoom = GL_TRUE;
98      yStep = (GLint) ctx->Pixel.ZoomY;
99      ASSERT(yStep == 1 || yStep == -1);
100   }
101   else {
102      /* non-simple zooming */
103      simpleZoom = GL_FALSE;
104      yStep = 1;
105      if (unpack.RowLength == 0)
106         unpack.RowLength = width;
107   }
108
109   /*
110    * Ready to draw!
111    */
112
113   if (format == GL_RGBA && type == rbType) {
114      const GLubyte *src
115         = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width,
116                                                   height, format, type, 0, 0);
117      const GLint srcStride = _mesa_image_row_stride(&unpack, width,
118                                                     format, type);
119      if (simpleZoom) {
120         GLint row;
121         for (row = 0; row < drawHeight; row++) {
122            rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
123            src += srcStride;
124            destY += yStep;
125         }
126      }
127      else {
128         /* with zooming */
129         GLint row;
130         for (row = 0; row < drawHeight; row++) {
131            span.x = destX;
132            span.y = destY + row;
133            span.end = drawWidth;
134            span.array->ChanType = rbType;
135            _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, src);
136            src += srcStride;
137         }
138         span.array->ChanType = CHAN_TYPE;
139      }
140      return GL_TRUE;
141   }
142
143   if (format == GL_RGB && type == rbType) {
144      const GLubyte *src
145         = (const GLubyte *) _mesa_image_address2d(&unpack, pixels, width,
146                                                   height, format, type, 0, 0);
147      const GLint srcStride = _mesa_image_row_stride(&unpack, width,
148                                                     format, type);
149      if (simpleZoom) {
150         GLint row;
151         for (row = 0; row < drawHeight; row++) {
152            rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
153            src += srcStride;
154            destY += yStep;
155         }
156      }
157      else {
158         /* with zooming */
159         GLint row;
160         for (row = 0; row < drawHeight; row++) {
161            span.x = destX;
162            span.y = destY;
163            span.end = drawWidth;
164            span.array->ChanType = rbType;
165            _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, src);
166            src += srcStride;
167            destY++;
168         }
169         span.array->ChanType = CHAN_TYPE;
170      }
171      return GL_TRUE;
172   }
173
174   /* Remaining cases haven't been tested with alignment != 1 */
175   if (userUnpack->Alignment != 1)
176      return GL_FALSE;
177
178   if (format == GL_LUMINANCE && type == CHAN_TYPE && rbType == CHAN_TYPE) {
179      const GLchan *src = (const GLchan *) pixels
180         + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels);
181      if (simpleZoom) {
182         /* no zooming */
183         GLint row;
184         ASSERT(drawWidth <= MAX_WIDTH);
185         for (row = 0; row < drawHeight; row++) {
186            GLchan rgb[MAX_WIDTH][3];
187            GLint i;
188            for (i = 0;i<drawWidth;i++) {
189               rgb[i][0] = src[i];
190               rgb[i][1] = src[i];
191               rgb[i][2] = src[i];
192            }
193            rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, rgb, NULL);
194            src += unpack.RowLength;
195            destY += yStep;
196         }
197      }
198      else {
199         /* with zooming */
200         GLint row;
201         ASSERT(drawWidth <= MAX_WIDTH);
202         for (row = 0; row < drawHeight; row++) {
203            GLchan rgb[MAX_WIDTH][3];
204            GLint i;
205            for (i = 0;i<drawWidth;i++) {
206               rgb[i][0] = src[i];
207               rgb[i][1] = src[i];
208               rgb[i][2] = src[i];
209            }
210            span.x = destX;
211            span.y = destY;
212            span.end = drawWidth;
213            _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span, rgb);
214            src += unpack.RowLength;
215            destY++;
216         }
217      }
218      return GL_TRUE;
219   }
220
221   if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE && rbType == CHAN_TYPE) {
222      const GLchan *src = (const GLchan *) pixels
223         + (unpack.SkipRows * unpack.RowLength + unpack.SkipPixels)*2;
224      if (simpleZoom) {
225         GLint row;
226         ASSERT(drawWidth <= MAX_WIDTH);
227         for (row = 0; row < drawHeight; row++) {
228            GLint i;
229            const GLchan *ptr = src;
230            for (i = 0;i<drawWidth;i++) {
231               span.array->rgba[i][0] = *ptr;
232               span.array->rgba[i][1] = *ptr;
233               span.array->rgba[i][2] = *ptr++;
234               span.array->rgba[i][3] = *ptr++;
235            }
236            rb->PutRow(ctx, rb, drawWidth, destX, destY,
237                       span.array->rgba, NULL);
238            src += unpack.RowLength*2;
239            destY += yStep;
240         }
241      }
242      else {
243         /* with zooming */
244         GLint row;
245         ASSERT(drawWidth <= MAX_WIDTH);
246         for (row = 0; row < drawHeight; row++) {
247            const GLchan *ptr = src;
248            GLint i;
249            for (i = 0;i<drawWidth;i++) {
250               span.array->rgba[i][0] = *ptr;
251               span.array->rgba[i][1] = *ptr;
252               span.array->rgba[i][2] = *ptr++;
253               span.array->rgba[i][3] = *ptr++;
254            }
255            span.x = destX;
256            span.y = destY;
257            span.end = drawWidth;
258            _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
259                                           span.array->rgba);
260            src += unpack.RowLength*2;
261            destY++;
262         }
263      }
264      return GL_TRUE;
265   }
266
267   if (format == GL_COLOR_INDEX && type == GL_UNSIGNED_BYTE) {
268      const GLubyte *src = (const GLubyte *) pixels
269         + unpack.SkipRows * unpack.RowLength + unpack.SkipPixels;
270      if (ctx->Visual.rgbMode && rbType == GL_UNSIGNED_BYTE) {
271         /* convert ubyte/CI data to ubyte/RGBA */
272         if (simpleZoom) {
273            GLint row;
274            for (row = 0; row < drawHeight; row++) {
275               ASSERT(drawWidth <= MAX_WIDTH);
276               _mesa_map_ci8_to_rgba8(ctx, drawWidth, src,
277                                      span.array->rgba8);
278               rb->PutRow(ctx, rb, drawWidth, destX, destY,
279                          span.array->rgba8, NULL);
280               src += unpack.RowLength;
281               destY += yStep;
282            }
283         }
284         else {
285            /* ubyte/CI to ubyte/RGBA with zooming */
286            GLint row;
287            for (row = 0; row < drawHeight; row++) {
288               ASSERT(drawWidth <= MAX_WIDTH);
289               _mesa_map_ci8_to_rgba8(ctx, drawWidth, src,
290                                      span.array->rgba8);
291               span.x = destX;
292               span.y = destY;
293               span.end = drawWidth;
294               _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
295                                              span.array->rgba8);
296               src += unpack.RowLength;
297               destY++;
298            }
299         }
300         return GL_TRUE;
301      }
302      else if (!ctx->Visual.rgbMode && rbType == GL_UNSIGNED_INT) {
303         /* write CI data to CI frame buffer */
304         GLint row;
305         if (simpleZoom) {
306            for (row = 0; row < drawHeight; row++) {
307               GLuint index32[MAX_WIDTH];
308               GLint col;
309               for (col = 0; col < drawWidth; col++)
310                  index32[col] = src[col];
311               rb->PutRow(ctx, rb, drawWidth, destX, destY, index32, NULL);
312               src += unpack.RowLength;
313               destY += yStep;
314            }
315            return GL_TRUE;
316         }
317      }
318   }
319
320   /* can't handle this pixel format and/or data type */
321   return GL_FALSE;
322}
323
324
325
326/*
327 * Draw color index image.
328 */
329static void
330draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
331                   GLsizei width, GLsizei height,
332                   GLenum type,
333                   const struct gl_pixelstore_attrib *unpack,
334                   const GLvoid *pixels )
335{
336   const GLint imgX = x, imgY = y;
337   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
338   GLint row, skipPixels;
339   SWspan span;
340
341   INIT_SPAN(span, GL_BITMAP);
342   span.arrayMask = SPAN_INDEX;
343   _swrast_span_default_attribs(ctx, &span);
344
345   /*
346    * General solution
347    */
348   skipPixels = 0;
349   while (skipPixels < width) {
350      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
351      ASSERT(spanWidth <= MAX_WIDTH);
352      for (row = 0; row < height; row++) {
353         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
354                                                      width, height,
355                                                      GL_COLOR_INDEX, type,
356                                                      row, skipPixels);
357         _mesa_unpack_index_span(ctx, spanWidth, GL_UNSIGNED_INT,
358                                 span.array->index, type, source, unpack,
359                                 ctx->_ImageTransferState);
360
361         /* These may get changed during writing/clipping */
362         span.x = x + skipPixels;
363         span.y = y + row;
364         span.end = spanWidth;
365
366         if (zoom)
367            _swrast_write_zoomed_index_span(ctx, imgX, imgY, &span);
368         else
369            _swrast_write_index_span(ctx, &span);
370      }
371      skipPixels += spanWidth;
372   }
373}
374
375
376
377/*
378 * Draw stencil image.
379 */
380static void
381draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
382                     GLsizei width, GLsizei height,
383                     GLenum type,
384                     const struct gl_pixelstore_attrib *unpack,
385                     const GLvoid *pixels )
386{
387   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
388   GLint skipPixels;
389
390   /* if width > MAX_WIDTH, have to process image in chunks */
391   skipPixels = 0;
392   while (skipPixels < width) {
393      const GLint spanX = x + skipPixels;
394      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
395      GLint row;
396      for (row = 0; row < height; row++) {
397         const GLint spanY = y + row;
398         GLstencil values[MAX_WIDTH];
399         GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
400                         ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
401         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
402                                                      width, height,
403                                                      GL_COLOR_INDEX, type,
404                                                      row, skipPixels);
405         _mesa_unpack_stencil_span(ctx, spanWidth, destType, values,
406                                   type, source, unpack,
407                                   ctx->_ImageTransferState);
408         if (zoom) {
409            _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
410                                              spanX, spanY, values);
411         }
412         else {
413            _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values);
414         }
415      }
416      skipPixels += spanWidth;
417   }
418}
419
420
421/*
422 * Draw depth image.
423 */
424static void
425draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
426                   GLsizei width, GLsizei height,
427                   GLenum type,
428                   const struct gl_pixelstore_attrib *unpack,
429                   const GLvoid *pixels )
430{
431   const GLboolean scaleOrBias
432      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
433   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
434   SWspan span;
435
436   INIT_SPAN(span, GL_BITMAP);
437   span.arrayMask = SPAN_Z;
438   _swrast_span_default_attribs(ctx, &span);
439
440   if (type == GL_UNSIGNED_SHORT
441       && ctx->DrawBuffer->Visual.depthBits == 16
442       && !scaleOrBias
443       && !zoom
444       && ctx->Visual.rgbMode
445       && width <= MAX_WIDTH
446       && !unpack->SwapBytes) {
447      /* Special case: directly write 16-bit depth values */
448      GLint row;
449      for (row = 0; row < height; row++) {
450         const GLushort *zSrc = (const GLushort *)
451            _mesa_image_address2d(unpack, pixels, width, height,
452                                  GL_DEPTH_COMPONENT, type, row, 0);
453         GLint i;
454         for (i = 0; i < width; i++)
455            span.array->z[i] = zSrc[i];
456         span.x = x;
457         span.y = y + row;
458         span.end = width;
459         _swrast_write_rgba_span(ctx, &span);
460      }
461   }
462   else if (type == GL_UNSIGNED_INT
463            && !scaleOrBias
464            && !zoom
465            && ctx->Visual.rgbMode
466            && width <= MAX_WIDTH
467            && !unpack->SwapBytes) {
468      /* Special case: shift 32-bit values down to Visual.depthBits */
469      const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
470      GLint row;
471      for (row = 0; row < height; row++) {
472         const GLuint *zSrc = (const GLuint *)
473            _mesa_image_address2d(unpack, pixels, width, height,
474                                  GL_DEPTH_COMPONENT, type, row, 0);
475         if (shift == 0) {
476            _mesa_memcpy(span.array->z, zSrc, width * sizeof(GLuint));
477         }
478         else {
479            GLint col;
480            for (col = 0; col < width; col++)
481               span.array->z[col] = zSrc[col] >> shift;
482         }
483         span.x = x;
484         span.y = y + row;
485         span.end = width;
486         _swrast_write_rgba_span(ctx, &span);
487      }
488   }
489   else {
490      /* General case */
491      const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
492      GLint skipPixels = 0;
493
494      /* in case width > MAX_WIDTH do the copy in chunks */
495      while (skipPixels < width) {
496         const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
497         GLint row;
498         ASSERT(span.end <= MAX_WIDTH);
499         for (row = 0; row < height; row++) {
500            const GLvoid *zSrc = _mesa_image_address2d(unpack,
501                                                      pixels, width, height,
502                                                      GL_DEPTH_COMPONENT, type,
503                                                      row, skipPixels);
504
505            /* Set these for each row since the _swrast_write_* function may
506             * change them while clipping.
507             */
508            span.x = x + skipPixels;
509            span.y = y + row;
510            span.end = spanWidth;
511
512            _mesa_unpack_depth_span(ctx, spanWidth,
513                                    GL_UNSIGNED_INT, span.array->z, depthMax,
514                                    type, zSrc, unpack);
515            if (zoom) {
516               _swrast_write_zoomed_depth_span(ctx, x, y, &span);
517            }
518            else if (ctx->Visual.rgbMode) {
519               _swrast_write_rgba_span(ctx, &span);
520            }
521            else {
522               _swrast_write_index_span(ctx, &span);
523            }
524         }
525         skipPixels += spanWidth;
526      }
527   }
528}
529
530
531
532/**
533 * Draw RGBA image.
534 */
535static void
536draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
537                  GLsizei width, GLsizei height,
538                  GLenum format, GLenum type,
539                  const struct gl_pixelstore_attrib *unpack,
540                  const GLvoid *pixels )
541{
542   const GLint imgX = x, imgY = y;
543   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
544   GLfloat *convImage = NULL;
545   GLbitfield transferOps = ctx->_ImageTransferState;
546   SWspan span;
547
548   /* Try an optimized glDrawPixels first */
549   if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
550                             unpack, pixels)) {
551      return;
552   }
553
554   INIT_SPAN(span, GL_BITMAP);
555   _swrast_span_default_attribs(ctx, &span);
556   span.arrayMask = SPAN_RGBA;
557   span.arrayAttribs = FRAG_BIT_COL0; /* we're fill in COL0 attrib values */
558
559   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
560      /* Convolution has to be handled specially.  We'll create an
561       * intermediate image, applying all pixel transfer operations
562       * up to convolution.  Then we'll convolve the image.  Then
563       * we'll proceed with the rest of the transfer operations and
564       * rasterize the image.
565       */
566      GLint row;
567      GLfloat *dest, *tmpImage;
568
569      tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
570      if (!tmpImage) {
571         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
572         return;
573      }
574      convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
575      if (!convImage) {
576         _mesa_free(tmpImage);
577         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
578         return;
579      }
580
581      /* Unpack the image and apply transfer ops up to convolution */
582      dest = tmpImage;
583      for (row = 0; row < height; row++) {
584         const GLvoid *source = _mesa_image_address2d(unpack,
585                                  pixels, width, height, format, type, row, 0);
586         _mesa_unpack_color_span_float(ctx, width, GL_RGBA, (GLfloat *) dest,
587                                     format, type, source, unpack,
588                                     transferOps & IMAGE_PRE_CONVOLUTION_BITS);
589         dest += width * 4;
590      }
591
592      /* do convolution */
593      if (ctx->Pixel.Convolution2DEnabled) {
594         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
595      }
596      else {
597         ASSERT(ctx->Pixel.Separable2DEnabled);
598         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
599      }
600      _mesa_free(tmpImage);
601
602      /* continue transfer ops and draw the convolved image */
603      unpack = &ctx->DefaultPacking;
604      pixels = convImage;
605      format = GL_RGBA;
606      type = GL_FLOAT;
607      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
608   }
609   else if (ctx->Pixel.Convolution1DEnabled) {
610      /* we only want to apply 1D convolution to glTexImage1D */
611      transferOps &= ~(IMAGE_CONVOLUTION_BIT |
612                       IMAGE_POST_CONVOLUTION_SCALE_BIAS);
613   }
614
615   if (ctx->DrawBuffer->_NumColorDrawBuffers > 0 &&
616       ctx->DrawBuffer->_ColorDrawBuffers[0]->DataType != GL_FLOAT &&
617       ctx->Color.ClampFragmentColor != GL_FALSE) {
618      /* need to clamp colors before applying fragment ops */
619      transferOps |= IMAGE_CLAMP_BIT;
620   }
621
622   /*
623    * General solution
624    */
625   {
626      const GLboolean sink = (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
627         || (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink);
628      const GLbitfield interpMask = span.interpMask;
629      const GLbitfield arrayMask = span.arrayMask;
630      const GLint srcStride
631         = _mesa_image_row_stride(unpack, width, format, type);
632      GLint skipPixels = 0;
633      /* use span array for temp color storage */
634      GLfloat *rgba = (GLfloat *) span.array->attribs[FRAG_ATTRIB_COL0];
635
636      /* if the span is wider than MAX_WIDTH we have to do it in chunks */
637      while (skipPixels < width) {
638         const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
639         const GLubyte *source
640            = (const GLubyte *) _mesa_image_address2d(unpack, pixels,
641                                                      width, height, format,
642                                                      type, 0, skipPixels);
643         GLint row;
644
645         for (row = 0; row < height; row++) {
646            /* get image row as float/RGBA */
647            _mesa_unpack_color_span_float(ctx, spanWidth, GL_RGBA, rgba,
648                                     format, type, source, unpack,
649                                     transferOps);
650            /* draw the span */
651            if (!sink) {
652               /* Set these for each row since the _swrast_write_* functions
653                * may change them while clipping/rendering.
654                */
655               span.array->ChanType = GL_FLOAT;
656               span.x = x + skipPixels;
657               span.y = y + row;
658               span.end = spanWidth;
659               span.arrayMask = arrayMask;
660               span.interpMask = interpMask;
661               if (zoom) {
662                  _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
663               }
664               else {
665                  _swrast_write_rgba_span(ctx, &span);
666               }
667            }
668
669            source += srcStride;
670         } /* for row */
671
672         skipPixels += spanWidth;
673      } /* while skipPixels < width */
674
675      /* XXX this is ugly/temporary, to undo above change */
676      span.array->ChanType = CHAN_TYPE;
677   }
678
679   if (convImage) {
680      _mesa_free(convImage);
681   }
682}
683
684
685/**
686 * This is a bit different from drawing GL_DEPTH_COMPONENT pixels.
687 * The only per-pixel operations that apply are depth scale/bias,
688 * stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK,
689 * and pixel zoom.
690 * Also, only the depth buffer and stencil buffers are touched, not the
691 * color buffer(s).
692 */
693static void
694draw_depth_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
695                          GLsizei width, GLsizei height, GLenum type,
696                          const struct gl_pixelstore_attrib *unpack,
697                          const GLvoid *pixels)
698{
699   const GLint imgX = x, imgY = y;
700   const GLboolean scaleOrBias
701      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
702   const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
703   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
704   const GLuint stencilType = (STENCIL_BITS == 8) ?
705      GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
706   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
707   struct gl_renderbuffer *depthRb, *stencilRb;
708   struct gl_pixelstore_attrib clippedUnpack = *unpack;
709
710   if (!zoom) {
711      if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
712                                 &clippedUnpack)) {
713         /* totally clipped */
714         return;
715      }
716   }
717
718   depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
719   stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
720   ASSERT(depthRb);
721   ASSERT(stencilRb);
722
723   if (depthRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
724       stencilRb->_BaseFormat == GL_DEPTH_STENCIL_EXT &&
725       depthRb == stencilRb &&
726       !scaleOrBias &&
727       !zoom &&
728       ctx->Depth.Mask &&
729       (stencilMask & 0xff) == 0xff) {
730      /* This is the ideal case.
731       * Drawing GL_DEPTH_STENCIL pixels into a combined depth/stencil buffer.
732       * Plus, no pixel transfer ops, zooming, or masking needed.
733       */
734      GLint i;
735      for (i = 0; i < height; i++) {
736         const GLuint *src = (const GLuint *)
737            _mesa_image_address2d(&clippedUnpack, pixels, width, height,
738                                  GL_DEPTH_STENCIL_EXT, type, i, 0);
739         depthRb->PutRow(ctx, depthRb, width, x, y + i, src, NULL);
740      }
741   }
742   else {
743      /* sub-optimal cases:
744       * Separate depth/stencil buffers, or pixel transfer ops required.
745       */
746      /* XXX need to handle very wide images (skippixels) */
747      GLint i;
748
749      depthRb = ctx->DrawBuffer->_DepthBuffer;
750      stencilRb = ctx->DrawBuffer->_StencilBuffer;
751
752      for (i = 0; i < height; i++) {
753         const GLuint *depthStencilSrc = (const GLuint *)
754            _mesa_image_address2d(&clippedUnpack, pixels, width, height,
755                                  GL_DEPTH_STENCIL_EXT, type, i, 0);
756
757         if (ctx->Depth.Mask) {
758            if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 24) {
759               /* fast path 24-bit zbuffer */
760               GLuint zValues[MAX_WIDTH];
761               GLint j;
762               ASSERT(depthRb->DataType == GL_UNSIGNED_INT);
763               for (j = 0; j < width; j++) {
764                  zValues[j] = depthStencilSrc[j] >> 8;
765               }
766               if (zoom)
767                  _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
768                                              x, y + i, zValues);
769               else
770                  depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
771            }
772            else if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 16) {
773               /* fast path 16-bit zbuffer */
774               GLushort zValues[MAX_WIDTH];
775               GLint j;
776               ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT);
777               for (j = 0; j < width; j++) {
778                  zValues[j] = depthStencilSrc[j] >> 16;
779               }
780               if (zoom)
781                  _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
782                                              x, y + i, zValues);
783               else
784                  depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
785            }
786            else {
787               /* general case */
788               GLuint zValues[MAX_WIDTH];  /* 16 or 32-bit Z value storage */
789               _mesa_unpack_depth_span(ctx, width,
790                                       depthRb->DataType, zValues, depthMax,
791                                       type, depthStencilSrc, &clippedUnpack);
792               if (zoom) {
793                  _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x,
794                                              y + i, zValues);
795               }
796               else {
797                  depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues,NULL);
798               }
799            }
800         }
801
802         if (stencilMask != 0x0) {
803            GLstencil stencilValues[MAX_WIDTH];
804            /* get stencil values, with shift/offset/mapping */
805            _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues,
806                                      type, depthStencilSrc, &clippedUnpack,
807                                      ctx->_ImageTransferState);
808            if (zoom)
809               _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width,
810                                                  x, y + i, stencilValues);
811            else
812               _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues);
813         }
814      }
815   }
816}
817
818
819/**
820 * Execute software-based glDrawPixels.
821 * By time we get here, all error checking will have been done.
822 */
823void
824_swrast_DrawPixels( GLcontext *ctx,
825		    GLint x, GLint y,
826		    GLsizei width, GLsizei height,
827		    GLenum format, GLenum type,
828		    const struct gl_pixelstore_attrib *unpack,
829		    const GLvoid *pixels )
830{
831   SWcontext *swrast = SWRAST_CONTEXT(ctx);
832
833   swrast_render_start(ctx);
834
835   if (ctx->NewState)
836      _mesa_update_state(ctx);
837
838   if (swrast->NewState)
839      _swrast_validate_derived( ctx );
840
841    pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels);
842    if (!pixels) {
843       swrast_render_finish(ctx);
844       return;
845    }
846
847   switch (format) {
848   case GL_STENCIL_INDEX:
849      draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
850      break;
851   case GL_DEPTH_COMPONENT:
852      draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
853      break;
854   case GL_COLOR_INDEX:
855      if (ctx->Visual.rgbMode)
856	 draw_rgba_pixels(ctx, x,y, width, height, format, type, unpack, pixels);
857      else
858	 draw_index_pixels(ctx, x, y, width, height, type, unpack, pixels);
859      break;
860   case GL_RED:
861   case GL_GREEN:
862   case GL_BLUE:
863   case GL_ALPHA:
864   case GL_LUMINANCE:
865   case GL_LUMINANCE_ALPHA:
866   case GL_RGB:
867   case GL_BGR:
868   case GL_RGBA:
869   case GL_BGRA:
870   case GL_ABGR_EXT:
871      draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
872      break;
873   case GL_DEPTH_STENCIL_EXT:
874      draw_depth_stencil_pixels(ctx, x, y, width, height,
875                                type, unpack, pixels);
876      break;
877   default:
878      _mesa_problem(ctx, "unexpected format in _swrast_DrawPixels");
879      /* don't return yet, clean-up */
880   }
881
882   swrast_render_finish(ctx);
883
884   _mesa_unmap_drapix_pbo(ctx, unpack);
885}
886
887
888
889#if 0  /* experimental */
890/*
891 * Execute glDrawDepthPixelsMESA().
892 */
893void
894_swrast_DrawDepthPixelsMESA( GLcontext *ctx,
895                             GLint x, GLint y,
896                             GLsizei width, GLsizei height,
897                             GLenum colorFormat, GLenum colorType,
898                             const GLvoid *colors,
899                             GLenum depthType, const GLvoid *depths,
900                             const struct gl_pixelstore_attrib *unpack )
901{
902   SWcontext *swrast = SWRAST_CONTEXT(ctx);
903
904   if (swrast->NewState)
905      _swrast_validate_derived( ctx );
906
907   swrast_render_start(ctx);
908
909   switch (colorFormat) {
910   case GL_COLOR_INDEX:
911      if (ctx->Visual.rgbMode)
912	 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType,
913                          unpack, colors);
914      else
915	 draw_index_pixels(ctx, x, y, width, height, colorType,
916                           unpack, colors);
917      break;
918   case GL_RED:
919   case GL_GREEN:
920   case GL_BLUE:
921   case GL_ALPHA:
922   case GL_LUMINANCE:
923   case GL_LUMINANCE_ALPHA:
924   case GL_RGB:
925   case GL_BGR:
926   case GL_RGBA:
927   case GL_BGRA:
928   case GL_ABGR_EXT:
929      draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType,
930                       unpack, colors);
931      break;
932   default:
933      _mesa_problem(ctx, "unexpected format in glDrawDepthPixelsMESA");
934   }
935
936   swrast_render_finish(ctx);
937}
938#endif
939