s_drawpix.c revision cb6b47b795e3865690defc809416e5b5b95f226a
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2005  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 "glheader.h"
27#include "bufferobj.h"
28#include "context.h"
29#include "convolve.h"
30#include "image.h"
31#include "macros.h"
32#include "imports.h"
33#include "pixel.h"
34
35#include "s_context.h"
36#include "s_drawpix.h"
37#include "s_pixeltex.h"
38#include "s_span.h"
39#include "s_stencil.h"
40#include "s_zoom.h"
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_pixels(GLcontext *ctx, GLint x, GLint y,
49                 GLsizei width, GLsizei height,
50                 GLenum format, GLenum type,
51                 const struct gl_pixelstore_attrib *unpack,
52                 const GLvoid *pixels)
53{
54   const GLint imgX = x, imgY = y;
55   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
56   SWcontext *swrast = SWRAST_CONTEXT(ctx);
57   struct sw_span span;
58
59   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
60
61   if (swrast->_RasterMask & MULTI_DRAW_BIT)
62      return GL_FALSE;
63
64   if (ctx->Depth.Test)
65      _swrast_span_default_z(ctx, &span);
66   if (swrast->_FogEnabled)
67      _swrast_span_default_fog(ctx, &span);
68   if (ctx->Texture._EnabledCoordUnits)
69      _swrast_span_default_texcoords(ctx, &span);
70
71   if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0
72       && ctx->Texture._EnabledCoordUnits == 0
73       && unpack->Alignment == 1
74       && !unpack->SwapBytes
75       && !unpack->LsbFirst) {
76
77      /* XXX there's a lot of clipping code here that should be replaced
78       * by a call to _mesa_clip_drawpixels().
79       */
80      GLint destX = x;
81      GLint destY = y;
82      GLint drawWidth = width;           /* actual width drawn */
83      GLint drawHeight = height;         /* actual height drawn */
84      GLint skipPixels = unpack->SkipPixels;
85      GLint skipRows = unpack->SkipRows;
86      GLint rowLength;
87
88      if (unpack->RowLength > 0)
89         rowLength = unpack->RowLength;
90      else
91         rowLength = width;
92
93      /* If we're not using pixel zoom then do all clipping calculations
94       * now.  Otherwise, we'll let the _swrast_write_zoomed_*_span() functions
95       * handle the clipping.
96       */
97      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
98         /* horizontal clipping */
99         if (destX < ctx->DrawBuffer->_Xmin) {
100            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
101            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
102            destX = ctx->DrawBuffer->_Xmin;
103         }
104         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
105            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
106         if (drawWidth <= 0)
107            return GL_TRUE;
108
109         /* vertical clipping */
110         if (destY < ctx->DrawBuffer->_Ymin) {
111            skipRows   += (ctx->DrawBuffer->_Ymin - destY);
112            drawHeight -= (ctx->DrawBuffer->_Ymin - destY);
113            destY = ctx->DrawBuffer->_Ymin;
114         }
115         if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
116            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
117         if (drawHeight <= 0)
118            return GL_TRUE;
119      }
120      else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
121         /* upside-down image */
122         /* horizontal clipping */
123         if (destX < ctx->DrawBuffer->_Xmin) {
124            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
125            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
126            destX = ctx->DrawBuffer->_Xmin;
127         }
128         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
129            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
130         if (drawWidth <= 0)
131            return GL_TRUE;
132
133         /* vertical clipping */
134         if (destY > ctx->DrawBuffer->_Ymax) {
135            skipRows   += (destY - ctx->DrawBuffer->_Ymax);
136            drawHeight -= (destY - ctx->DrawBuffer->_Ymax);
137            destY = ctx->DrawBuffer->_Ymax;
138         }
139         if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
140            drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
141         if (drawHeight <= 0)
142            return GL_TRUE;
143      }
144      else {
145         if (drawWidth > MAX_WIDTH)
146            return GL_FALSE; /* fall back to general case path */
147      }
148
149
150      /*
151       * Ready to draw!
152       * The window region at (destX, destY) of size (drawWidth, drawHeight)
153       * will be written to.
154       * We'll take pixel data from buffer pointed to by "pixels" but we'll
155       * skip "skipRows" rows and skip "skipPixels" pixels/row.
156       */
157
158      if (format == GL_RGBA && type == CHAN_TYPE
159          && ctx->_ImageTransferState==0) {
160         if (ctx->Visual.rgbMode) {
161            GLchan *src = (GLchan *) pixels
162               + (skipRows * rowLength + skipPixels) * 4;
163            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
164               /* no zooming */
165               GLint row;
166               for (row=0; row<drawHeight; row++) {
167                  rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
168                  src += rowLength * 4;
169                  destY++;
170               }
171            }
172            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
173               /* upside-down */
174               GLint row;
175               for (row=0; row<drawHeight; row++) {
176                  destY--;
177                  rb->PutRow(ctx, rb, drawWidth, destX, destY, src, NULL);
178                  src += rowLength * 4;
179               }
180            }
181            else {
182               /* with zooming */
183               GLint row;
184               for (row=0; row<drawHeight; row++) {
185                  span.x = destX;
186                  span.y = destY + row;
187                  span.end = drawWidth;
188                  _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
189                                                 (CONST GLchan (*)[4]) src);
190                  src += rowLength * 4;
191               }
192            }
193         }
194         return GL_TRUE;
195      }
196      else if (format == GL_RGB && type == CHAN_TYPE
197               && ctx->_ImageTransferState == 0) {
198         if (ctx->Visual.rgbMode) {
199            GLchan *src = (GLchan *) pixels
200               + (skipRows * rowLength + skipPixels) * 3;
201            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
202               GLint row;
203               for (row=0; row<drawHeight; row++) {
204                  rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
205                  src += rowLength * 3;
206                  destY++;
207               }
208            }
209            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
210               /* upside-down */
211               GLint row;
212               for (row=0; row<drawHeight; row++) {
213                  destY--;
214                  rb->PutRowRGB(ctx, rb, drawWidth, destX, destY, src, NULL);
215                  src += rowLength * 3;
216               }
217            }
218            else {
219               /* with zooming */
220               GLint row;
221               for (row=0; row<drawHeight; row++) {
222                  span.x = destX;
223                  span.y = destY;
224                  span.end = drawWidth;
225                  _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span,
226                                         (CONST GLchan (*)[3]) src);
227                  src += rowLength * 3;
228                  destY++;
229               }
230            }
231         }
232         return GL_TRUE;
233      }
234      else if (format == GL_LUMINANCE && type == CHAN_TYPE
235               && ctx->_ImageTransferState==0) {
236         if (ctx->Visual.rgbMode) {
237            GLchan *src = (GLchan *) pixels
238               + (skipRows * rowLength + skipPixels);
239            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
240               /* no zooming */
241               GLint row;
242               ASSERT(drawWidth <= MAX_WIDTH);
243               for (row=0; row<drawHeight; row++) {
244                  GLint i;
245		  for (i=0;i<drawWidth;i++) {
246                     span.array->rgb[i][0] = src[i];
247                     span.array->rgb[i][1] = src[i];
248                     span.array->rgb[i][2] = src[i];
249		  }
250                  rb->PutRowRGB(ctx, rb, drawWidth, destX, destY,
251                                span.array->rgb, NULL);
252                  src += rowLength;
253                  destY++;
254               }
255            }
256            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
257               /* upside-down */
258               GLint row;
259               ASSERT(drawWidth <= MAX_WIDTH);
260               for (row=0; row<drawHeight; row++) {
261                  GLint i;
262                  for (i=0;i<drawWidth;i++) {
263                     span.array->rgb[i][0] = src[i];
264                     span.array->rgb[i][1] = src[i];
265                     span.array->rgb[i][2] = src[i];
266                  }
267                  destY--;
268                  rb->PutRow(ctx, rb, drawWidth, destX, destY,
269                             span.array->rgb, NULL);
270                  src += rowLength;
271               }
272            }
273            else {
274               /* with zooming */
275               GLint row;
276               ASSERT(drawWidth <= MAX_WIDTH);
277               for (row=0; row<drawHeight; row++) {
278                  GLint i;
279		  for (i=0;i<drawWidth;i++) {
280                     span.array->rgb[i][0] = src[i];
281                     span.array->rgb[i][1] = src[i];
282                     span.array->rgb[i][2] = src[i];
283		  }
284                  span.x = destX;
285                  span.y = destY;
286                  span.end = drawWidth;
287                  _swrast_write_zoomed_rgb_span(ctx, imgX, imgY, &span,
288                             (CONST GLchan (*)[3]) span.array->rgb);
289                  src += rowLength;
290                  destY++;
291               }
292            }
293         }
294         return GL_TRUE;
295      }
296      else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
297               && ctx->_ImageTransferState == 0) {
298         if (ctx->Visual.rgbMode) {
299            GLchan *src = (GLchan *) pixels
300               + (skipRows * rowLength + skipPixels)*2;
301            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
302               /* no zooming */
303               GLint row;
304               ASSERT(drawWidth <= MAX_WIDTH);
305               for (row=0; row<drawHeight; row++) {
306                  GLint i;
307                  GLchan *ptr = src;
308		  for (i=0;i<drawWidth;i++) {
309                     span.array->rgba[i][0] = *ptr;
310                     span.array->rgba[i][1] = *ptr;
311                     span.array->rgba[i][2] = *ptr++;
312                     span.array->rgba[i][3] = *ptr++;
313		  }
314                  rb->PutRow(ctx, rb, drawWidth, destX, destY,
315                             span.array->rgba, NULL);
316                  src += rowLength*2;
317                  destY++;
318               }
319            }
320            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
321               /* upside-down */
322               GLint row;
323               ASSERT(drawWidth <= MAX_WIDTH);
324               for (row=0; row<drawHeight; row++) {
325                  GLint i;
326                  GLchan *ptr = src;
327                  for (i=0;i<drawWidth;i++) {
328                     span.array->rgba[i][0] = *ptr;
329                     span.array->rgba[i][1] = *ptr;
330                     span.array->rgba[i][2] = *ptr++;
331                     span.array->rgba[i][3] = *ptr++;
332                  }
333                  destY--;
334                  rb->PutRow(ctx, rb, drawWidth, destX, destY,
335                             span.array->rgba, NULL);
336                  src += rowLength*2;
337               }
338            }
339            else {
340               /* with zooming */
341               GLint row;
342               ASSERT(drawWidth <= MAX_WIDTH);
343               for (row=0; row<drawHeight; row++) {
344                  GLchan *ptr = src;
345                  GLint i;
346		  for (i=0;i<drawWidth;i++) {
347                     span.array->rgba[i][0] = *ptr;
348                     span.array->rgba[i][1] = *ptr;
349                     span.array->rgba[i][2] = *ptr++;
350                     span.array->rgba[i][3] = *ptr++;
351		  }
352                  span.x = destX;
353                  span.y = destY;
354                  span.end = drawWidth;
355                  _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
356                            (CONST GLchan (*)[4]) span.array->rgba);
357                  src += rowLength*2;
358                  destY++;
359               }
360            }
361         }
362         return GL_TRUE;
363      }
364      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
365         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
366         if (ctx->Visual.rgbMode) {
367            /* convert CI data to RGBA */
368            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
369               /* no zooming */
370               GLint row;
371               for (row=0; row<drawHeight; row++) {
372                  ASSERT(drawWidth <= MAX_WIDTH);
373                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
374                  rb->PutRow(ctx, rb, drawWidth, destX, destY,
375                             span.array->rgba, NULL);
376                  src += rowLength;
377                  destY++;
378               }
379               return GL_TRUE;
380            }
381            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
382               /* upside-down */
383               GLint row;
384               for (row=0; row<drawHeight; row++) {
385                  ASSERT(drawWidth <= MAX_WIDTH);
386                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
387                  destY--;
388                  rb->PutRow(ctx, rb, drawWidth, destX, destY,
389                             span.array->rgba, NULL);
390                  src += rowLength;
391               }
392               return GL_TRUE;
393            }
394            else {
395               /* with zooming */
396               GLint row;
397               for (row=0; row<drawHeight; row++) {
398                  ASSERT(drawWidth <= MAX_WIDTH);
399                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.array->rgba);
400                  span.x = destX;
401                  span.y = destY;
402                  span.end = drawWidth;
403                  _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
404                            (CONST GLchan (*)[4]) span.array->rgba);
405                  src += rowLength;
406                  destY++;
407               }
408               return GL_TRUE;
409            }
410         }
411         else if (ctx->_ImageTransferState==0) {
412            /* write CI data to CI frame buffer */
413            GLint row;
414            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
415               /* no zooming */
416               for (row=0; row<drawHeight; row++) {
417                  GLuint index32[MAX_WIDTH];
418                  GLint col;
419                  for (col = 0; col < drawWidth; col++)
420                     index32[col] = src[col];
421                  rb->PutRow(ctx, rb, drawWidth, destX, destY, index32, NULL);
422                  src += rowLength;
423                  destY++;
424               }
425               return GL_TRUE;
426            }
427            else {
428               /* with zooming */
429               return GL_FALSE;
430            }
431         }
432      }
433      else {
434         /* can't handle this pixel format and/or data type here */
435         return GL_FALSE;
436      }
437   }
438
439   /* can't do a simple draw, have to use slow path */
440   return GL_FALSE;
441}
442
443
444
445/*
446 * Draw color index image.
447 */
448static void
449draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
450                   GLsizei width, GLsizei height,
451                   GLenum type,
452                   const struct gl_pixelstore_attrib *unpack,
453                   const GLvoid *pixels )
454{
455   SWcontext *swrast = SWRAST_CONTEXT(ctx);
456   const GLint imgX = x, imgY = y;
457   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
458   GLint row, skipPixels;
459   struct sw_span span;
460
461   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
462
463   if (ctx->Depth.Test)
464      _swrast_span_default_z(ctx, &span);
465   if (swrast->_FogEnabled)
466      _swrast_span_default_fog(ctx, &span);
467
468   /*
469    * General solution
470    */
471   skipPixels = 0;
472   while (skipPixels < width) {
473      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
474      ASSERT(spanWidth <= MAX_WIDTH);
475      for (row = 0; row < height; row++) {
476         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
477                                                      width, height,
478                                                      GL_COLOR_INDEX, type,
479                                                      row, skipPixels);
480         _mesa_unpack_index_span(ctx, spanWidth, GL_UNSIGNED_INT,
481                                 span.array->index, type, source, unpack,
482                                 ctx->_ImageTransferState);
483
484         /* These may get changed during writing/clipping */
485         span.x = x + skipPixels;
486         span.y = y + row;
487         span.end = spanWidth;
488
489         if (zoom)
490            _swrast_write_zoomed_index_span(ctx, imgX, imgY, &span);
491         else
492            _swrast_write_index_span(ctx, &span);
493      }
494      skipPixels += spanWidth;
495   }
496}
497
498
499
500/*
501 * Draw stencil image.
502 */
503static void
504draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
505                     GLsizei width, GLsizei height,
506                     GLenum type,
507                     const struct gl_pixelstore_attrib *unpack,
508                     const GLvoid *pixels )
509{
510   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
511   GLint skipPixels;
512
513   /* if width > MAX_WIDTH, have to process image in chunks */
514   skipPixels = 0;
515   while (skipPixels < width) {
516      const GLint spanX = x + skipPixels;
517      const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
518      GLint row;
519      for (row = 0; row < height; row++) {
520         const GLint spanY = y + row;
521         GLstencil values[MAX_WIDTH];
522         GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
523                         ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
524         const GLvoid *source = _mesa_image_address2d(unpack, pixels,
525                                                      width, height,
526                                                      GL_COLOR_INDEX, type,
527                                                      row, skipPixels);
528         _mesa_unpack_index_span(ctx, spanWidth, destType, values,
529                                 type, source, unpack,
530                                 ctx->_ImageTransferState);
531         if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
532            _mesa_shift_and_offset_stencil(ctx, spanWidth, values);
533         }
534         if (ctx->Pixel.MapStencilFlag) {
535            _mesa_map_stencil(ctx, spanWidth, values);
536         }
537
538         if (zoom) {
539            _swrast_write_zoomed_stencil_span(ctx, x, y, spanWidth,
540                                              spanX, spanY, values);
541         }
542         else {
543            _swrast_write_stencil_span(ctx, spanWidth, spanX, spanY, values);
544         }
545      }
546      skipPixels += spanWidth;
547   }
548}
549
550
551/*
552 * Draw depth image.
553 */
554static void
555draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
556                   GLsizei width, GLsizei height,
557                   GLenum type,
558                   const struct gl_pixelstore_attrib *unpack,
559                   const GLvoid *pixels )
560{
561   SWcontext *swrast = SWRAST_CONTEXT(ctx);
562   const GLboolean scaleOrBias
563      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
564   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
565   struct sw_span span;
566
567   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
568
569   _swrast_span_default_color(ctx, &span);
570
571   if (swrast->_FogEnabled)
572      _swrast_span_default_fog(ctx, &span);
573   if (ctx->Texture._EnabledCoordUnits)
574      _swrast_span_default_texcoords(ctx, &span);
575
576   if (type == GL_UNSIGNED_SHORT
577       && ctx->DrawBuffer->Visual.depthBits == 16
578       && !scaleOrBias
579       && !zoom
580       && ctx->Visual.rgbMode
581       && width <= MAX_WIDTH) {
582      /* Special case: directly write 16-bit depth values */
583      GLint row;
584      for (row = 0; row < height; row++) {
585         const GLushort *zSrc = (const GLushort *)
586            _mesa_image_address2d(unpack, pixels, width, height,
587                                  GL_DEPTH_COMPONENT, type, row, 0);
588         GLint i;
589         for (i = 0; i < width; i++)
590            span.array->z[i] = zSrc[i];
591         span.x = x;
592         span.y = y + row;
593         span.end = width;
594         _swrast_write_rgba_span(ctx, &span);
595      }
596   }
597   else if (type == GL_UNSIGNED_INT
598            && !scaleOrBias
599            && !zoom
600            && ctx->Visual.rgbMode
601            && width <= MAX_WIDTH) {
602      /* Special case: shift 32-bit values down to Visual.depthBits */
603      const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
604      GLint row;
605      for (row = 0; row < height; row++) {
606         const GLuint *zSrc = (const GLuint *)
607            _mesa_image_address2d(unpack, pixels, width, height,
608                                  GL_DEPTH_COMPONENT, type, row, 0);
609         if (shift == 0) {
610            MEMCPY(span.array->z, zSrc, width * sizeof(GLuint));
611         }
612         else {
613            GLint col;
614            for (col = 0; col < width; col++)
615               span.array->z[col] = zSrc[col] >> shift;
616         }
617         span.x = x;
618         span.y = y + row;
619         span.end = width;
620         _swrast_write_rgba_span(ctx, &span);
621      }
622   }
623   else {
624      /* General case */
625      const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
626      GLint skipPixels = 0;
627
628      /* in case width > MAX_WIDTH do the copy in chunks */
629      while (skipPixels < width) {
630         const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
631         GLint row;
632         ASSERT(span.end <= MAX_WIDTH);
633         for (row = 0; row < height; row++) {
634            const GLvoid *zSrc = _mesa_image_address2d(unpack,
635                                                      pixels, width, height,
636                                                      GL_DEPTH_COMPONENT, type,
637                                                      row, skipPixels);
638
639            /* Set these for each row since the _swrast_write_* function may
640             * change them while clipping.
641             */
642            span.x = x + skipPixels;
643            span.y = y + row;
644            span.end = spanWidth;
645
646            _mesa_unpack_depth_span(ctx, spanWidth,
647                                    GL_UNSIGNED_INT, span.array->z, depthMax,
648                                    type, zSrc, unpack);
649            if (zoom) {
650               _swrast_write_zoomed_depth_span(ctx, x, y, &span);
651            }
652            else if (ctx->Visual.rgbMode) {
653               _swrast_write_rgba_span(ctx, &span);
654            }
655            else {
656               _swrast_write_index_span(ctx, &span);
657            }
658         }
659         skipPixels += spanWidth;
660      }
661   }
662}
663
664
665
666/*
667 * Draw RGBA image.
668 */
669static void
670draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
671                  GLsizei width, GLsizei height,
672                  GLenum format, GLenum type,
673                  const struct gl_pixelstore_attrib *unpack,
674                  const GLvoid *pixels )
675{
676   SWcontext *swrast = SWRAST_CONTEXT(ctx);
677   const GLint imgX = x, imgY = y;
678   struct gl_renderbuffer *rb = NULL; /* only used for quickDraw path */
679   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
680   GLboolean quickDraw;
681   GLfloat *convImage = NULL;
682   GLuint transferOps = ctx->_ImageTransferState;
683   struct sw_span span;
684
685   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
686
687   /* Try an optimized glDrawPixels first */
688   if (fast_draw_pixels(ctx, x, y, width, height, format, type, unpack, pixels))
689      return;
690
691   if (ctx->Depth.Test)
692      _swrast_span_default_z(ctx, &span);
693   if (swrast->_FogEnabled)
694      _swrast_span_default_fog(ctx, &span);
695   if (ctx->Texture._EnabledCoordUnits)
696      _swrast_span_default_texcoords(ctx, &span);
697
698   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
699       && x + width <= (GLint) ctx->DrawBuffer->Width
700       && y + height <= (GLint) ctx->DrawBuffer->Height
701       && ctx->DrawBuffer->_NumColorDrawBuffers[0] == 1) {
702      quickDraw = GL_TRUE;
703      rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
704   }
705   else {
706      quickDraw = GL_FALSE;
707      rb = NULL;
708   }
709
710   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
711      /* Convolution has to be handled specially.  We'll create an
712       * intermediate image, applying all pixel transfer operations
713       * up to convolution.  Then we'll convolve the image.  Then
714       * we'll proceed with the rest of the transfer operations and
715       * rasterize the image.
716       */
717      GLint row;
718      GLfloat *dest, *tmpImage;
719
720      tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
721      if (!tmpImage) {
722         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
723         return;
724      }
725      convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
726      if (!convImage) {
727         _mesa_free(tmpImage);
728         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
729         return;
730      }
731
732      /* Unpack the image and apply transfer ops up to convolution */
733      dest = tmpImage;
734      for (row = 0; row < height; row++) {
735         const GLvoid *source = _mesa_image_address2d(unpack,
736                                  pixels, width, height, format, type, row, 0);
737         _mesa_unpack_color_span_float(ctx, width, GL_RGBA, (GLfloat *) dest,
738                                     format, type, source, unpack,
739                                     transferOps & IMAGE_PRE_CONVOLUTION_BITS);
740         dest += width * 4;
741      }
742
743      /* do convolution */
744      if (ctx->Pixel.Convolution2DEnabled) {
745         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
746      }
747      else {
748         ASSERT(ctx->Pixel.Separable2DEnabled);
749         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
750      }
751      _mesa_free(tmpImage);
752
753      /* continue transfer ops and draw the convolved image */
754      unpack = &ctx->DefaultPacking;
755      pixels = convImage;
756      format = GL_RGBA;
757      type = GL_FLOAT;
758      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
759   }
760
761   /*
762    * General solution
763    */
764   {
765      const GLbitfield interpMask = span.interpMask;
766      const GLbitfield arrayMask = span.arrayMask;
767      GLint skipPixels = 0;
768
769      /* if the span is wider than MAX_WIDTH we have to do it in chunks */
770      while (skipPixels < width) {
771         const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
772         GLint row;
773
774         ASSERT(span.end <= MAX_WIDTH);
775
776         for (row = 0; row < height; row++) {
777            const GLvoid *source = _mesa_image_address2d(unpack,
778                     pixels, width, height, format, type, row, skipPixels);
779
780            /* Set these for each row since the _swrast_write_* function may
781             * change them while clipping.
782             */
783            span.x = x + skipPixels;
784            span.y = y + row;
785            span.end = spanWidth;
786            span.arrayMask = arrayMask;
787            span.interpMask = interpMask;
788
789            _mesa_unpack_color_span_chan(ctx, spanWidth, GL_RGBA,
790                                         (GLchan *) span.array->rgba,
791                                         format, type, source, unpack,
792                                         transferOps);
793
794            if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
795                (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
796               continue;
797
798            if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
799               _swrast_pixel_texture(ctx, &span);
800            }
801
802            /* draw the span */
803            if (quickDraw) {
804               rb->PutRow(ctx, rb, span.end, span.x, span.y,
805                          span.array->rgba, NULL);
806            }
807            else if (zoom) {
808               _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span,
809                                       (CONST GLchan (*)[4]) span.array->rgba);
810            }
811            else {
812               _swrast_write_rgba_span(ctx, &span);
813            }
814         }
815
816         skipPixels += spanWidth;
817      }
818   }
819
820   if (convImage) {
821      _mesa_free(convImage);
822   }
823}
824
825
826
827static void
828draw_depth_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
829                          GLsizei width, GLsizei height, GLenum type,
830                          const struct gl_pixelstore_attrib *unpack,
831                          const GLvoid *pixels)
832{
833   const GLint imgX = x, imgY = y;
834   const GLboolean scaleOrBias =
835      ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
836   const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
837   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
838   const GLuint stencilType = (STENCIL_BITS == 8) ?
839      GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
840   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
841   struct gl_renderbuffer *depthRb, *stencilRb;
842   struct gl_pixelstore_attrib clippedUnpack = *unpack;
843   GLint i;
844
845   depthRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
846   stencilRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
847
848   ASSERT(depthRb);
849   ASSERT(stencilRb);
850
851   if (!zoom) {
852      if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
853                                 &clippedUnpack)) {
854         /* totally clipped */
855         return;
856      }
857   }
858
859   /* XXX need to handle very wide images (skippixels) */
860
861   for (i = 0; i < height; i++) {
862      const GLuint *depthStencilSrc = (const GLuint *)
863         _mesa_image_address2d(&clippedUnpack, pixels, width, height,
864                               GL_DEPTH_STENCIL_EXT, type, i, 0);
865
866      if (ctx->Depth.Mask) {
867         if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 24) {
868            /* fast path 24-bit zbuffer */
869            GLuint zValues[MAX_WIDTH];
870            GLint j;
871            ASSERT(depthRb->DataType == GL_UNSIGNED_INT);
872            for (j = 0; j < width; j++) {
873               zValues[j] = depthStencilSrc[j] >> 8;
874            }
875            if (zoom)
876               _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
877                                           x, y + i, zValues);
878            else
879               depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues, NULL);
880         }
881         else if (!scaleOrBias && ctx->DrawBuffer->Visual.depthBits == 16) {
882            /* fast path 16-bit zbuffer */
883            GLushort zValues[MAX_WIDTH];
884            GLint j;
885            ASSERT(depthRb->DataType == GL_UNSIGNED_SHORT);
886            for (j = 0; j < width; j++) {
887               zValues[j] = depthStencilSrc[j] >> 16;
888            }
889            if (zoom)
890               _swrast_write_zoomed_z_span(ctx, imgX, imgY, width,
891                                           x, y + i, zValues);
892            else
893               depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues, NULL);
894         }
895         else {
896            /* general case */
897            GLuint zValues[MAX_WIDTH];  /* 16 or 32-bit Z value storage */
898            _mesa_unpack_depth_span(ctx, width,
899                                    depthRb->DataType, zValues, depthScale,
900                                    type, depthStencilSrc, &clippedUnpack);
901            if (zoom) {
902               _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x,
903                                           y + i, zValues);
904            }
905            else {
906               depthRb->PutRow(ctx, depthRb, width, x, y + i, zValues, NULL);
907            }
908         }
909      }
910
911      if (stencilMask != 0x0) {
912         GLstencil stencilValues[MAX_WIDTH];
913         /* get stencil values, with shift/offset/mapping */
914         _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues,
915                                   type, depthStencilSrc, &clippedUnpack,
916                                   ctx->_ImageTransferState);
917         if (zoom)
918            _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width,
919                                               x, y + i, stencilValues);
920         else
921            _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues);
922      }
923
924   }
925}
926
927
928
929/**
930 * Execute software-based glDrawPixels.
931 * By time we get here, all error checking will have been done.
932 */
933void
934_swrast_DrawPixels( GLcontext *ctx,
935		    GLint x, GLint y,
936		    GLsizei width, GLsizei height,
937		    GLenum format, GLenum type,
938		    const struct gl_pixelstore_attrib *unpack,
939		    const GLvoid *pixels )
940{
941   SWcontext *swrast = SWRAST_CONTEXT(ctx);
942
943   if (swrast->NewState)
944      _swrast_validate_derived( ctx );
945
946   if (unpack->BufferObj->Name) {
947      /* unpack from PBO */
948      GLubyte *buf;
949      if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
950                                     format, type, pixels)) {
951         _mesa_error(ctx, GL_INVALID_OPERATION,
952                     "glDrawPixels(invalid PBO access)");
953         return;
954      }
955      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
956                                              GL_READ_ONLY_ARB,
957                                              unpack->BufferObj);
958      if (!buf) {
959         /* buffer is already mapped - that's an error */
960         _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)");
961         return;
962      }
963      pixels = ADD_POINTERS(buf, pixels);
964   }
965
966   RENDER_START(swrast,ctx);
967
968   switch (format) {
969   case GL_STENCIL_INDEX:
970      draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
971      break;
972   case GL_DEPTH_COMPONENT:
973      draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
974      break;
975   case GL_COLOR_INDEX:
976      if (ctx->Visual.rgbMode)
977	 draw_rgba_pixels(ctx, x,y, width, height, format, type, unpack, pixels);
978      else
979	 draw_index_pixels(ctx, x, y, width, height, type, unpack, pixels);
980      break;
981   case GL_RED:
982   case GL_GREEN:
983   case GL_BLUE:
984   case GL_ALPHA:
985   case GL_LUMINANCE:
986   case GL_LUMINANCE_ALPHA:
987   case GL_RGB:
988   case GL_BGR:
989   case GL_RGBA:
990   case GL_BGRA:
991   case GL_ABGR_EXT:
992      draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
993      break;
994   case GL_DEPTH_STENCIL_EXT:
995      draw_depth_stencil_pixels(ctx, x, y, width, height,
996                                type, unpack, pixels);
997      break;
998   default:
999      _mesa_problem(ctx, "unexpected format in _swrast_DrawPixels");
1000      /* don't return yet, clean-up */
1001   }
1002
1003   RENDER_FINISH(swrast,ctx);
1004
1005   if (unpack->BufferObj->Name) {
1006      /* done with PBO so unmap it now */
1007      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
1008                              unpack->BufferObj);
1009   }
1010}
1011
1012
1013
1014#if 0  /* experimental */
1015/*
1016 * Execute glDrawDepthPixelsMESA().
1017 */
1018void
1019_swrast_DrawDepthPixelsMESA( GLcontext *ctx,
1020                             GLint x, GLint y,
1021                             GLsizei width, GLsizei height,
1022                             GLenum colorFormat, GLenum colorType,
1023                             const GLvoid *colors,
1024                             GLenum depthType, const GLvoid *depths,
1025                             const struct gl_pixelstore_attrib *unpack )
1026{
1027   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1028
1029   if (swrast->NewState)
1030      _swrast_validate_derived( ctx );
1031
1032   RENDER_START(swrast,ctx);
1033
1034   switch (colorFormat) {
1035   case GL_COLOR_INDEX:
1036      if (ctx->Visual.rgbMode)
1037	 draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType,
1038                          unpack, colors);
1039      else
1040	 draw_index_pixels(ctx, x, y, width, height, colorType,
1041                           unpack, colors);
1042      break;
1043   case GL_RED:
1044   case GL_GREEN:
1045   case GL_BLUE:
1046   case GL_ALPHA:
1047   case GL_LUMINANCE:
1048   case GL_LUMINANCE_ALPHA:
1049   case GL_RGB:
1050   case GL_BGR:
1051   case GL_RGBA:
1052   case GL_BGRA:
1053   case GL_ABGR_EXT:
1054      draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType,
1055                       unpack, colors);
1056      break;
1057   default:
1058      _mesa_problem(ctx, "unexpected format in glDrawDepthPixelsMESA");
1059   }
1060
1061   RENDER_FINISH(swrast,ctx);
1062}
1063#endif
1064