17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
26c1f859d4Smrg#include "main/glheader.h"
27c1f859d4Smrg#include "main/bufferobj.h"
28af69d88dSmrg#include "main/colormac.h"
29cdc920a0Smrg#include "main/condrender.h"
30c1f859d4Smrg#include "main/context.h"
31af69d88dSmrg#include "main/format_pack.h"
3201e04c3fSmrg#include "main/format_utils.h"
3301e04c3fSmrg#include "main/glformats.h"
34c1f859d4Smrg#include "main/image.h"
357ec681f3Smrg
363464ebd5Sriastradh#include "main/macros.h"
373464ebd5Sriastradh#include "main/pack.h"
383464ebd5Sriastradh#include "main/pbo.h"
393464ebd5Sriastradh#include "main/pixeltransfer.h"
40c1f859d4Smrg#include "main/state.h"
417117f1b4Smrg
427117f1b4Smrg#include "s_context.h"
437117f1b4Smrg#include "s_span.h"
447117f1b4Smrg#include "s_stencil.h"
457117f1b4Smrg#include "s_zoom.h"
467117f1b4Smrg
477117f1b4Smrg
48af69d88dSmrg/**
49af69d88dSmrg * Handle a common case of drawing GL_RGB/GL_UNSIGNED_BYTE into a
50af69d88dSmrg * MESA_FORMAT_XRGB888 or MESA_FORMAT_ARGB888 renderbuffer.
51af69d88dSmrg */
52af69d88dSmrgstatic void
53af69d88dSmrgfast_draw_rgb_ubyte_pixels(struct gl_context *ctx,
54af69d88dSmrg                           struct gl_renderbuffer *rb,
55af69d88dSmrg                           GLint x, GLint y,
56af69d88dSmrg                           GLsizei width, GLsizei height,
57af69d88dSmrg                           const struct gl_pixelstore_attrib *unpack,
5801e04c3fSmrg                           const GLvoid *pixels,
5901e04c3fSmrg                           bool flip_y)
60af69d88dSmrg{
61af69d88dSmrg   const GLubyte *src = (const GLubyte *)
62af69d88dSmrg      _mesa_image_address2d(unpack, pixels, width,
63af69d88dSmrg                            height, GL_RGB, GL_UNSIGNED_BYTE, 0, 0);
64af69d88dSmrg   const GLint srcRowStride = _mesa_image_row_stride(unpack, width,
65af69d88dSmrg                                                     GL_RGB, GL_UNSIGNED_BYTE);
66af69d88dSmrg   GLint i, j;
67af69d88dSmrg   GLubyte *dst;
68af69d88dSmrg   GLint dstRowStride;
69af69d88dSmrg
70af69d88dSmrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
7101e04c3fSmrg                               GL_MAP_WRITE_BIT, &dst, &dstRowStride,
7201e04c3fSmrg                               flip_y);
73af69d88dSmrg
74af69d88dSmrg   if (!dst) {
75af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
76af69d88dSmrg      return;
77af69d88dSmrg   }
78af69d88dSmrg
79af69d88dSmrg   if (ctx->Pixel.ZoomY == -1.0f) {
80af69d88dSmrg      dst = dst + (height - 1) * dstRowStride;
81af69d88dSmrg      dstRowStride = -dstRowStride;
82af69d88dSmrg   }
83af69d88dSmrg
84af69d88dSmrg   for (i = 0; i < height; i++) {
85af69d88dSmrg      GLuint *dst4 = (GLuint *) dst;
86af69d88dSmrg      for (j = 0; j < width; j++) {
87af69d88dSmrg         dst4[j] = PACK_COLOR_8888(0xff, src[j*3+0], src[j*3+1], src[j*3+2]);
88af69d88dSmrg      }
89af69d88dSmrg      dst += dstRowStride;
90af69d88dSmrg      src += srcRowStride;
91af69d88dSmrg   }
92af69d88dSmrg
93af69d88dSmrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
94af69d88dSmrg}
95af69d88dSmrg
96af69d88dSmrg
97af69d88dSmrg/**
98af69d88dSmrg * Handle a common case of drawing GL_RGBA/GL_UNSIGNED_BYTE into a
99af69d88dSmrg * MESA_FORMAT_ARGB888 or MESA_FORMAT_xRGB888 renderbuffer.
100af69d88dSmrg */
101af69d88dSmrgstatic void
102af69d88dSmrgfast_draw_rgba_ubyte_pixels(struct gl_context *ctx,
103af69d88dSmrg                           struct gl_renderbuffer *rb,
104af69d88dSmrg                           GLint x, GLint y,
105af69d88dSmrg                           GLsizei width, GLsizei height,
106af69d88dSmrg                           const struct gl_pixelstore_attrib *unpack,
10701e04c3fSmrg                           const GLvoid *pixels,
10801e04c3fSmrg                           bool flip_y)
109af69d88dSmrg{
110af69d88dSmrg   const GLubyte *src = (const GLubyte *)
111af69d88dSmrg      _mesa_image_address2d(unpack, pixels, width,
112af69d88dSmrg                            height, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
113af69d88dSmrg   const GLint srcRowStride =
114af69d88dSmrg      _mesa_image_row_stride(unpack, width, GL_RGBA, GL_UNSIGNED_BYTE);
115af69d88dSmrg   GLint i, j;
116af69d88dSmrg   GLubyte *dst;
117af69d88dSmrg   GLint dstRowStride;
118af69d88dSmrg
119af69d88dSmrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
12001e04c3fSmrg                               GL_MAP_WRITE_BIT, &dst, &dstRowStride,
12101e04c3fSmrg                               flip_y);
122af69d88dSmrg
123af69d88dSmrg   if (!dst) {
124af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
125af69d88dSmrg      return;
126af69d88dSmrg   }
127af69d88dSmrg
128af69d88dSmrg   if (ctx->Pixel.ZoomY == -1.0f) {
129af69d88dSmrg      dst = dst + (height - 1) * dstRowStride;
130af69d88dSmrg      dstRowStride = -dstRowStride;
131af69d88dSmrg   }
132af69d88dSmrg
133af69d88dSmrg   for (i = 0; i < height; i++) {
134af69d88dSmrg      GLuint *dst4 = (GLuint *) dst;
135af69d88dSmrg      for (j = 0; j < width; j++) {
136af69d88dSmrg         dst4[j] = PACK_COLOR_8888(src[j*4+3], src[j*4+0],
137af69d88dSmrg                                   src[j*4+1], src[j*4+2]);
138af69d88dSmrg      }
139af69d88dSmrg      dst += dstRowStride;
140af69d88dSmrg      src += srcRowStride;
141af69d88dSmrg   }
142af69d88dSmrg
143af69d88dSmrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
144af69d88dSmrg}
145af69d88dSmrg
146af69d88dSmrg
147af69d88dSmrg/**
148af69d88dSmrg * Handle a common case of drawing a format/type combination that
149af69d88dSmrg * exactly matches the renderbuffer format.
150af69d88dSmrg */
151af69d88dSmrgstatic void
152af69d88dSmrgfast_draw_generic_pixels(struct gl_context *ctx,
153af69d88dSmrg                         struct gl_renderbuffer *rb,
154af69d88dSmrg                         GLint x, GLint y,
155af69d88dSmrg                         GLsizei width, GLsizei height,
156af69d88dSmrg                         GLenum format, GLenum type,
157af69d88dSmrg                         const struct gl_pixelstore_attrib *unpack,
15801e04c3fSmrg                         const GLvoid *pixels,
15901e04c3fSmrg                         bool flip_y)
160af69d88dSmrg{
161af69d88dSmrg   const GLubyte *src = (const GLubyte *)
162af69d88dSmrg      _mesa_image_address2d(unpack, pixels, width,
163af69d88dSmrg                            height, format, type, 0, 0);
164af69d88dSmrg   const GLint srcRowStride =
165af69d88dSmrg      _mesa_image_row_stride(unpack, width, format, type);
166af69d88dSmrg   const GLint rowLength = width * _mesa_get_format_bytes(rb->Format);
167af69d88dSmrg   GLint i;
168af69d88dSmrg   GLubyte *dst;
169af69d88dSmrg   GLint dstRowStride;
170af69d88dSmrg
171af69d88dSmrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
17201e04c3fSmrg                               GL_MAP_WRITE_BIT, &dst, &dstRowStride,
17301e04c3fSmrg                               flip_y);
174af69d88dSmrg
175af69d88dSmrg   if (!dst) {
176af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
177af69d88dSmrg      return;
178af69d88dSmrg   }
179af69d88dSmrg
180af69d88dSmrg   if (ctx->Pixel.ZoomY == -1.0f) {
181af69d88dSmrg      dst = dst + (height - 1) * dstRowStride;
182af69d88dSmrg      dstRowStride = -dstRowStride;
183af69d88dSmrg   }
184af69d88dSmrg
185af69d88dSmrg   for (i = 0; i < height; i++) {
186af69d88dSmrg      memcpy(dst, src, rowLength);
187af69d88dSmrg      dst += dstRowStride;
188af69d88dSmrg      src += srcRowStride;
189af69d88dSmrg   }
190af69d88dSmrg
191af69d88dSmrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
192af69d88dSmrg}
193af69d88dSmrg
1947117f1b4Smrg
1957117f1b4Smrg/**
1967117f1b4Smrg * Try to do a fast and simple RGB(a) glDrawPixels.
1977117f1b4Smrg * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
1987117f1b4Smrg */
1997117f1b4Smrgstatic GLboolean
2003464ebd5Sriastradhfast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y,
2017117f1b4Smrg                      GLsizei width, GLsizei height,
2027117f1b4Smrg                      GLenum format, GLenum type,
2037117f1b4Smrg                      const struct gl_pixelstore_attrib *userUnpack,
2047117f1b4Smrg                      const GLvoid *pixels)
2057117f1b4Smrg{
20601e04c3fSmrg   struct gl_framebuffer *fb = ctx->DrawBuffer;
207c1f859d4Smrg   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
2087117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
2097117f1b4Smrg   struct gl_pixelstore_attrib unpack;
2107117f1b4Smrg
211c1f859d4Smrg   if (!rb)
212c1f859d4Smrg      return GL_TRUE; /* no-op */
213c1f859d4Smrg
214af69d88dSmrg   if (ctx->DrawBuffer->_NumColorDrawBuffers > 1 ||
215af69d88dSmrg       (swrast->_RasterMask & ~CLIP_BIT) ||
2167117f1b4Smrg       ctx->Texture._EnabledCoordUnits ||
2177117f1b4Smrg       userUnpack->SwapBytes ||
218af69d88dSmrg       ctx->Pixel.ZoomX != 1.0f ||
219af69d88dSmrg       fabsf(ctx->Pixel.ZoomY) != 1.0f ||
2207117f1b4Smrg       ctx->_ImageTransferState) {
2217117f1b4Smrg      /* can't handle any of those conditions */
2227117f1b4Smrg      return GL_FALSE;
2237117f1b4Smrg   }
2247117f1b4Smrg
2257117f1b4Smrg   unpack = *userUnpack;
2267117f1b4Smrg
227af69d88dSmrg   /* clipping */
228af69d88dSmrg   if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &unpack)) {
229af69d88dSmrg      /* image was completely clipped: no-op, all done */
2307117f1b4Smrg      return GL_TRUE;
2317117f1b4Smrg   }
2327117f1b4Smrg
233af69d88dSmrg   if (format == GL_RGB &&
234af69d88dSmrg       type == GL_UNSIGNED_BYTE &&
235af69d88dSmrg       (rb->Format == MESA_FORMAT_B8G8R8X8_UNORM ||
236af69d88dSmrg        rb->Format == MESA_FORMAT_B8G8R8A8_UNORM)) {
237af69d88dSmrg      fast_draw_rgb_ubyte_pixels(ctx, rb, x, y, width, height,
23801e04c3fSmrg                                 &unpack, pixels, fb->FlipY);
2397117f1b4Smrg      return GL_TRUE;
2407117f1b4Smrg   }
2417117f1b4Smrg
242af69d88dSmrg   if (format == GL_RGBA &&
243af69d88dSmrg       type == GL_UNSIGNED_BYTE &&
244af69d88dSmrg       (rb->Format == MESA_FORMAT_B8G8R8X8_UNORM ||
245af69d88dSmrg        rb->Format == MESA_FORMAT_B8G8R8A8_UNORM)) {
246af69d88dSmrg      fast_draw_rgba_ubyte_pixels(ctx, rb, x, y, width, height,
24701e04c3fSmrg                                  &unpack, pixels, fb->FlipY);
2487117f1b4Smrg      return GL_TRUE;
2497117f1b4Smrg   }
2507117f1b4Smrg
251af69d88dSmrg   if (_mesa_format_matches_format_and_type(rb->Format, format, type,
25201e04c3fSmrg                                            ctx->Unpack.SwapBytes, NULL)) {
253af69d88dSmrg      fast_draw_generic_pixels(ctx, rb, x, y, width, height,
25401e04c3fSmrg                               format, type, &unpack, pixels,
25501e04c3fSmrg                               fb->FlipY);
2567117f1b4Smrg      return GL_TRUE;
2577117f1b4Smrg   }
2587117f1b4Smrg
2597117f1b4Smrg   /* can't handle this pixel format and/or data type */
2607117f1b4Smrg   return GL_FALSE;
2617117f1b4Smrg}
2627117f1b4Smrg
2637117f1b4Smrg
2647117f1b4Smrg
2657117f1b4Smrg/*
2667117f1b4Smrg * Draw stencil image.
2677117f1b4Smrg */
2687117f1b4Smrgstatic void
2693464ebd5Sriastradhdraw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y,
2707117f1b4Smrg                     GLsizei width, GLsizei height,
2717117f1b4Smrg                     GLenum type,
2727117f1b4Smrg                     const struct gl_pixelstore_attrib *unpack,
2737117f1b4Smrg                     const GLvoid *pixels )
2747117f1b4Smrg{
27501e04c3fSmrg   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
276af69d88dSmrg   const GLenum destType = GL_UNSIGNED_BYTE;
277af69d88dSmrg   GLint row;
278af69d88dSmrg   GLubyte *values;
2797117f1b4Smrg
280af69d88dSmrg   values = malloc(width * sizeof(GLubyte));
281af69d88dSmrg   if (!values) {
282af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
283af69d88dSmrg      return;
284af69d88dSmrg   }
285af69d88dSmrg
286af69d88dSmrg   for (row = 0; row < height; row++) {
287af69d88dSmrg      const GLvoid *source = _mesa_image_address2d(unpack, pixels,
288af69d88dSmrg                                                   width, height,
289af69d88dSmrg                                                   GL_STENCIL_INDEX, type,
290af69d88dSmrg                                                   row, 0);
291af69d88dSmrg      _mesa_unpack_stencil_span(ctx, width, destType, values,
292af69d88dSmrg                                type, source, unpack,
293af69d88dSmrg                                ctx->_ImageTransferState);
294af69d88dSmrg      if (zoom) {
295af69d88dSmrg         _swrast_write_zoomed_stencil_span(ctx, x, y, width,
296af69d88dSmrg                                           x, y, values);
2977117f1b4Smrg      }
298af69d88dSmrg      else {
299af69d88dSmrg         _swrast_write_stencil_span(ctx, width, x, y, values);
300af69d88dSmrg      }
301af69d88dSmrg
302af69d88dSmrg      y++;
3037117f1b4Smrg   }
304af69d88dSmrg
305af69d88dSmrg   free(values);
3067117f1b4Smrg}
3077117f1b4Smrg
3087117f1b4Smrg
3097117f1b4Smrg/*
3107117f1b4Smrg * Draw depth image.
3117117f1b4Smrg */
3127117f1b4Smrgstatic void
3133464ebd5Sriastradhdraw_depth_pixels( struct gl_context *ctx, GLint x, GLint y,
3147117f1b4Smrg                   GLsizei width, GLsizei height,
3157117f1b4Smrg                   GLenum type,
3167117f1b4Smrg                   const struct gl_pixelstore_attrib *unpack,
3177117f1b4Smrg                   const GLvoid *pixels )
3187117f1b4Smrg{
3197117f1b4Smrg   const GLboolean scaleOrBias
32001e04c3fSmrg      = ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;
32101e04c3fSmrg   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0f || ctx->Pixel.ZoomY != 1.0f;
3227117f1b4Smrg   SWspan span;
3237117f1b4Smrg
324c1f859d4Smrg   INIT_SPAN(span, GL_BITMAP);
325c1f859d4Smrg   span.arrayMask = SPAN_Z;
326c1f859d4Smrg   _swrast_span_default_attribs(ctx, &span);
3277117f1b4Smrg
3287117f1b4Smrg   if (type == GL_UNSIGNED_SHORT
3297117f1b4Smrg       && ctx->DrawBuffer->Visual.depthBits == 16
3307117f1b4Smrg       && !scaleOrBias
3317117f1b4Smrg       && !zoom
332af69d88dSmrg       && width <= SWRAST_MAX_WIDTH
3337117f1b4Smrg       && !unpack->SwapBytes) {
3347117f1b4Smrg      /* Special case: directly write 16-bit depth values */
3357117f1b4Smrg      GLint row;
3367117f1b4Smrg      for (row = 0; row < height; row++) {
3377117f1b4Smrg         const GLushort *zSrc = (const GLushort *)
3387117f1b4Smrg            _mesa_image_address2d(unpack, pixels, width, height,
3397117f1b4Smrg                                  GL_DEPTH_COMPONENT, type, row, 0);
3407117f1b4Smrg         GLint i;
3417117f1b4Smrg         for (i = 0; i < width; i++)
3427117f1b4Smrg            span.array->z[i] = zSrc[i];
3437117f1b4Smrg         span.x = x;
3447117f1b4Smrg         span.y = y + row;
3457117f1b4Smrg         span.end = width;
3467117f1b4Smrg         _swrast_write_rgba_span(ctx, &span);
3477117f1b4Smrg      }
3487117f1b4Smrg   }
3497117f1b4Smrg   else if (type == GL_UNSIGNED_INT
3507117f1b4Smrg            && !scaleOrBias
3517117f1b4Smrg            && !zoom
352af69d88dSmrg            && width <= SWRAST_MAX_WIDTH
3537117f1b4Smrg            && !unpack->SwapBytes) {
3547117f1b4Smrg      /* Special case: shift 32-bit values down to Visual.depthBits */
3557117f1b4Smrg      const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
3567117f1b4Smrg      GLint row;
3577117f1b4Smrg      for (row = 0; row < height; row++) {
3587117f1b4Smrg         const GLuint *zSrc = (const GLuint *)
3597117f1b4Smrg            _mesa_image_address2d(unpack, pixels, width, height,
3607117f1b4Smrg                                  GL_DEPTH_COMPONENT, type, row, 0);
3617117f1b4Smrg         if (shift == 0) {
362cdc920a0Smrg            memcpy(span.array->z, zSrc, width * sizeof(GLuint));
3637117f1b4Smrg         }
3647117f1b4Smrg         else {
3657117f1b4Smrg            GLint col;
3667117f1b4Smrg            for (col = 0; col < width; col++)
3677117f1b4Smrg               span.array->z[col] = zSrc[col] >> shift;
3687117f1b4Smrg         }
3697117f1b4Smrg         span.x = x;
3707117f1b4Smrg         span.y = y + row;
3717117f1b4Smrg         span.end = width;
3727117f1b4Smrg         _swrast_write_rgba_span(ctx, &span);
3737117f1b4Smrg      }
3747117f1b4Smrg   }
3757117f1b4Smrg   else {
3767117f1b4Smrg      /* General case */
377c1f859d4Smrg      const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
3787117f1b4Smrg      GLint skipPixels = 0;
3797117f1b4Smrg
380af69d88dSmrg      /* in case width > SWRAST_MAX_WIDTH do the copy in chunks */
3817117f1b4Smrg      while (skipPixels < width) {
382af69d88dSmrg         const GLint spanWidth = MIN2(width - skipPixels, SWRAST_MAX_WIDTH);
3837117f1b4Smrg         GLint row;
38401e04c3fSmrg         assert(span.end <= SWRAST_MAX_WIDTH);
3857117f1b4Smrg         for (row = 0; row < height; row++) {
3867117f1b4Smrg            const GLvoid *zSrc = _mesa_image_address2d(unpack,
3877117f1b4Smrg                                                      pixels, width, height,
3887117f1b4Smrg                                                      GL_DEPTH_COMPONENT, type,
3897117f1b4Smrg                                                      row, skipPixels);
3907117f1b4Smrg
3917117f1b4Smrg            /* Set these for each row since the _swrast_write_* function may
3927117f1b4Smrg             * change them while clipping.
3937117f1b4Smrg             */
3947117f1b4Smrg            span.x = x + skipPixels;
3957117f1b4Smrg            span.y = y + row;
3967117f1b4Smrg            span.end = spanWidth;
3977117f1b4Smrg
3987117f1b4Smrg            _mesa_unpack_depth_span(ctx, spanWidth,
3997117f1b4Smrg                                    GL_UNSIGNED_INT, span.array->z, depthMax,
4007117f1b4Smrg                                    type, zSrc, unpack);
4017117f1b4Smrg            if (zoom) {
4027117f1b4Smrg               _swrast_write_zoomed_depth_span(ctx, x, y, &span);
4037117f1b4Smrg            }
4047117f1b4Smrg            else {
405cdc920a0Smrg               _swrast_write_rgba_span(ctx, &span);
4067117f1b4Smrg            }
4077117f1b4Smrg         }
4087117f1b4Smrg         skipPixels += spanWidth;
4097117f1b4Smrg      }
4107117f1b4Smrg   }
4117117f1b4Smrg}
4127117f1b4Smrg
4137117f1b4Smrg
4147117f1b4Smrg
4157117f1b4Smrg/**
4167117f1b4Smrg * Draw RGBA image.
4177117f1b4Smrg */
4187117f1b4Smrgstatic void
4193464ebd5Sriastradhdraw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y,
4207117f1b4Smrg                  GLsizei width, GLsizei height,
4217117f1b4Smrg                  GLenum format, GLenum type,
4227117f1b4Smrg                  const struct gl_pixelstore_attrib *unpack,
4237117f1b4Smrg                  const GLvoid *pixels )
4247117f1b4Smrg{
4257117f1b4Smrg   const GLint imgX = x, imgY = y;
42601e04c3fSmrg   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
4277117f1b4Smrg   GLbitfield transferOps = ctx->_ImageTransferState;
4287117f1b4Smrg   SWspan span;
4297117f1b4Smrg
4307117f1b4Smrg   /* Try an optimized glDrawPixels first */
4317117f1b4Smrg   if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
432c1f859d4Smrg                             unpack, pixels)) {
4337117f1b4Smrg      return;
434c1f859d4Smrg   }
4357117f1b4Smrg
436af69d88dSmrg   swrast_render_start(ctx);
437af69d88dSmrg
438c1f859d4Smrg   INIT_SPAN(span, GL_BITMAP);
439c1f859d4Smrg   _swrast_span_default_attribs(ctx, &span);
440c1f859d4Smrg   span.arrayMask = SPAN_RGBA;
441af69d88dSmrg   span.arrayAttribs = VARYING_BIT_COL0; /* we're fill in COL0 attrib values */
442af69d88dSmrg
443af69d88dSmrg   if (ctx->DrawBuffer->_NumColorDrawBuffers > 0) {
444af69d88dSmrg      GLenum datatype = _mesa_get_format_datatype(
445af69d88dSmrg                 ctx->DrawBuffer->_ColorDrawBuffers[0]->Format);
446af69d88dSmrg      if (datatype != GL_FLOAT &&
447af69d88dSmrg          ctx->Color.ClampFragmentColor != GL_FALSE) {
448af69d88dSmrg         /* need to clamp colors before applying fragment ops */
449af69d88dSmrg         transferOps |= IMAGE_CLAMP_BIT;
450af69d88dSmrg      }
4517117f1b4Smrg   }
4527117f1b4Smrg
4537117f1b4Smrg   /*
4547117f1b4Smrg    * General solution
4557117f1b4Smrg    */
4567117f1b4Smrg   {
4577117f1b4Smrg      const GLbitfield interpMask = span.interpMask;
4587117f1b4Smrg      const GLbitfield arrayMask = span.arrayMask;
4597117f1b4Smrg      GLint skipPixels = 0;
4607117f1b4Smrg      /* use span array for temp color storage */
461af69d88dSmrg      GLfloat *rgba = (GLfloat *) span.array->attribs[VARYING_SLOT_COL0];
46201e04c3fSmrg      void *tempImage = NULL;
46301e04c3fSmrg
46401e04c3fSmrg      /* We have to deal with GL_COLOR_INDEX manually because
46501e04c3fSmrg       * _mesa_format_convert does not handle this format. So what we do here is
46601e04c3fSmrg       * convert it to RGBA ubyte first and then convert from that to dst as
46701e04c3fSmrg       * usual.
46801e04c3fSmrg       */
46901e04c3fSmrg      if (format == GL_COLOR_INDEX) {
47001e04c3fSmrg         /* This will handle byte swapping and transferops if needed */
47101e04c3fSmrg         tempImage =
47201e04c3fSmrg            _mesa_unpack_color_index_to_rgba_ubyte(ctx, 2,
47301e04c3fSmrg                                                   pixels, format, type,
47401e04c3fSmrg                                                   width, height, 1,
47501e04c3fSmrg                                                   unpack,
47601e04c3fSmrg                                                   transferOps);
47701e04c3fSmrg         if (!tempImage) {
47801e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
47901e04c3fSmrg            return;
48001e04c3fSmrg         }
48101e04c3fSmrg
48201e04c3fSmrg         transferOps = 0;
48301e04c3fSmrg         pixels = tempImage;
48401e04c3fSmrg         format = GL_RGBA;
48501e04c3fSmrg         type = GL_UNSIGNED_BYTE;
48601e04c3fSmrg      } else if (unpack->SwapBytes) {
48701e04c3fSmrg         /* We have to handle byte-swapping scenarios before calling
48801e04c3fSmrg          * _mesa_format_convert
48901e04c3fSmrg          */
49001e04c3fSmrg         GLint swapSize = _mesa_sizeof_packed_type(type);
49101e04c3fSmrg         if (swapSize == 2 || swapSize == 4) {
49201e04c3fSmrg            int imageStride = _mesa_image_image_stride(unpack, width, height, format, type);
49301e04c3fSmrg
49401e04c3fSmrg            tempImage = malloc(imageStride);
49501e04c3fSmrg            if (!tempImage) {
49601e04c3fSmrg               _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
49701e04c3fSmrg               return;
49801e04c3fSmrg            }
49901e04c3fSmrg
50001e04c3fSmrg            _mesa_swap_bytes_2d_image(format, type, unpack,
50101e04c3fSmrg                                      width, height, tempImage, pixels);
50201e04c3fSmrg
50301e04c3fSmrg            pixels = tempImage;
50401e04c3fSmrg         }
50501e04c3fSmrg      }
50601e04c3fSmrg
50701e04c3fSmrg      const GLint srcStride
50801e04c3fSmrg         = _mesa_image_row_stride(unpack, width, format, type);
5097117f1b4Smrg
510af69d88dSmrg      /* if the span is wider than SWRAST_MAX_WIDTH we have to do it in chunks */
5117117f1b4Smrg      while (skipPixels < width) {
512af69d88dSmrg         const GLint spanWidth = MIN2(width - skipPixels, SWRAST_MAX_WIDTH);
5137117f1b4Smrg         const GLubyte *source
5147117f1b4Smrg            = (const GLubyte *) _mesa_image_address2d(unpack, pixels,
5157117f1b4Smrg                                                      width, height, format,
5167117f1b4Smrg                                                      type, 0, skipPixels);
5177117f1b4Smrg         GLint row;
5187117f1b4Smrg
51901e04c3fSmrg         /* get image row as float/RGBA */
52001e04c3fSmrg         uint32_t srcMesaFormat = _mesa_format_from_format_and_type(format, type);
5217117f1b4Smrg         for (row = 0; row < height; row++) {
52201e04c3fSmrg            int dstRowStride = 4 * width * sizeof(float);
52301e04c3fSmrg            _mesa_format_convert(rgba, RGBA32_FLOAT, dstRowStride,
52401e04c3fSmrg                                 (void*)source, srcMesaFormat, srcStride,
52501e04c3fSmrg                                 spanWidth, 1, NULL);
52601e04c3fSmrg            if (transferOps)
52701e04c3fSmrg               _mesa_apply_rgba_transfer_ops(ctx, transferOps, spanWidth, (GLfloat (*)[4])rgba);
5283464ebd5Sriastradh	    /* Set these for each row since the _swrast_write_* functions
5293464ebd5Sriastradh	     * may change them while clipping/rendering.
5303464ebd5Sriastradh	     */
5313464ebd5Sriastradh	    span.array->ChanType = GL_FLOAT;
5323464ebd5Sriastradh	    span.x = x + skipPixels;
5333464ebd5Sriastradh	    span.y = y + row;
5343464ebd5Sriastradh	    span.end = spanWidth;
5353464ebd5Sriastradh	    span.arrayMask = arrayMask;
5363464ebd5Sriastradh	    span.interpMask = interpMask;
5373464ebd5Sriastradh	    if (zoom) {
5383464ebd5Sriastradh	       _swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
5393464ebd5Sriastradh	    }
5403464ebd5Sriastradh	    else {
5413464ebd5Sriastradh	       _swrast_write_rgba_span(ctx, &span);
5423464ebd5Sriastradh	    }
5437117f1b4Smrg
5447117f1b4Smrg            source += srcStride;
5457117f1b4Smrg         } /* for row */
5467117f1b4Smrg
5477117f1b4Smrg         skipPixels += spanWidth;
5487117f1b4Smrg      } /* while skipPixels < width */
5497117f1b4Smrg
5507117f1b4Smrg      /* XXX this is ugly/temporary, to undo above change */
5517117f1b4Smrg      span.array->ChanType = CHAN_TYPE;
5527117f1b4Smrg
55301e04c3fSmrg      free(tempImage);
55401e04c3fSmrg   }
555af69d88dSmrg
556af69d88dSmrg   swrast_render_finish(ctx);
557af69d88dSmrg}
558af69d88dSmrg
5597ec681f3Smrg/**
5607ec681f3Smrg * Incoming Z/stencil values are always in uint_24_8 format.
5617ec681f3Smrg */
5627ec681f3Smrgstatic void
5637ec681f3Smrgpack_uint_24_8_depth_stencil_row(mesa_format format, uint32_t n,
5647ec681f3Smrg                                       const uint32_t *src, void *dst)
5657ec681f3Smrg{
5667ec681f3Smrg   switch (format) {
5677ec681f3Smrg   case MESA_FORMAT_S8_UINT_Z24_UNORM:
5687ec681f3Smrg      memcpy(dst, src, n * sizeof(uint32_t));
5697ec681f3Smrg      break;
5707ec681f3Smrg   case MESA_FORMAT_Z24_UNORM_S8_UINT:
5717ec681f3Smrg      {
5727ec681f3Smrg         uint32_t *d = ((uint32_t *) dst);
5737ec681f3Smrg         uint32_t i;
5747ec681f3Smrg         for (i = 0; i < n; i++) {
5757ec681f3Smrg            uint32_t s = src[i] << 24;
5767ec681f3Smrg            uint32_t z = src[i] >> 8;
5777ec681f3Smrg            d[i] = s | z;
5787ec681f3Smrg         }
5797ec681f3Smrg      }
5807ec681f3Smrg      break;
5817ec681f3Smrg   default:
5827ec681f3Smrg      unreachable("bad format in _mesa_pack_ubyte_s_row");
5837ec681f3Smrg   }
5847ec681f3Smrg}
585af69d88dSmrg
586af69d88dSmrg/**
587af69d88dSmrg * Draw depth+stencil values into a MESA_FORAMT_Z24_S8 or MESA_FORMAT_Z24_UNORM_S8_UINT
588af69d88dSmrg * renderbuffer.  No masking, zooming, scaling, etc.
589af69d88dSmrg */
590af69d88dSmrgstatic void
591af69d88dSmrgfast_draw_depth_stencil(struct gl_context *ctx, GLint x, GLint y,
592af69d88dSmrg                        GLsizei width, GLsizei height,
593af69d88dSmrg                        const struct gl_pixelstore_attrib *unpack,
594af69d88dSmrg                        const GLvoid *pixels)
595af69d88dSmrg{
596af69d88dSmrg   const GLenum format = GL_DEPTH_STENCIL_EXT;
597af69d88dSmrg   const GLenum type = GL_UNSIGNED_INT_24_8;
598af69d88dSmrg   struct gl_renderbuffer *rb =
599af69d88dSmrg      ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
600af69d88dSmrg   struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
601af69d88dSmrg   GLubyte *src, *dst;
602af69d88dSmrg   GLint srcRowStride, dstRowStride;
603af69d88dSmrg   GLint i;
604af69d88dSmrg
605af69d88dSmrg   src = _mesa_image_address2d(unpack, pixels, width, height,
606af69d88dSmrg                               format, type, 0, 0);
607af69d88dSmrg   srcRowStride = _mesa_image_row_stride(unpack, width, format, type);
608af69d88dSmrg
609af69d88dSmrg   dst = _swrast_pixel_address(rb, x, y);
610af69d88dSmrg   dstRowStride = srb->RowStride;
611af69d88dSmrg
612af69d88dSmrg   for (i = 0; i < height; i++) {
6137ec681f3Smrg      pack_uint_24_8_depth_stencil_row(rb->Format, width, (const GLuint *) src, dst);
614af69d88dSmrg      dst += dstRowStride;
615af69d88dSmrg      src += srcRowStride;
6167117f1b4Smrg   }
6177117f1b4Smrg}
6187117f1b4Smrg
6197117f1b4Smrg
620af69d88dSmrg
6217117f1b4Smrg/**
6227117f1b4Smrg * This is a bit different from drawing GL_DEPTH_COMPONENT pixels.
6237117f1b4Smrg * The only per-pixel operations that apply are depth scale/bias,
6247117f1b4Smrg * stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK,
6257117f1b4Smrg * and pixel zoom.
6267117f1b4Smrg * Also, only the depth buffer and stencil buffers are touched, not the
6277117f1b4Smrg * color buffer(s).
6287117f1b4Smrg */
6297117f1b4Smrgstatic void
6303464ebd5Sriastradhdraw_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
6317117f1b4Smrg                          GLsizei width, GLsizei height, GLenum type,
6327117f1b4Smrg                          const struct gl_pixelstore_attrib *unpack,
6337117f1b4Smrg                          const GLvoid *pixels)
6347117f1b4Smrg{
6357117f1b4Smrg   const GLint imgX = x, imgY = y;
6367117f1b4Smrg   const GLboolean scaleOrBias
63701e04c3fSmrg      = ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F;
6387117f1b4Smrg   const GLuint stencilMask = ctx->Stencil.WriteMask[0];
639af69d88dSmrg   const GLenum stencilType = GL_UNSIGNED_BYTE;
64001e04c3fSmrg   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
6417117f1b4Smrg   struct gl_renderbuffer *depthRb, *stencilRb;
6427117f1b4Smrg   struct gl_pixelstore_attrib clippedUnpack = *unpack;
6437117f1b4Smrg
6447117f1b4Smrg   if (!zoom) {
6457117f1b4Smrg      if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
6467117f1b4Smrg                                 &clippedUnpack)) {
6477117f1b4Smrg         /* totally clipped */
6487117f1b4Smrg         return;
6497117f1b4Smrg      }
6507117f1b4Smrg   }
6517ec681f3Smrg
6527117f1b4Smrg   depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
6537117f1b4Smrg   stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
65401e04c3fSmrg   assert(depthRb);
65501e04c3fSmrg   assert(stencilRb);
6567117f1b4Smrg
657af69d88dSmrg   if (depthRb == stencilRb &&
658af69d88dSmrg       (depthRb->Format == MESA_FORMAT_S8_UINT_Z24_UNORM ||
659af69d88dSmrg        depthRb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT) &&
660af69d88dSmrg       type == GL_UNSIGNED_INT_24_8 &&
6617117f1b4Smrg       !scaleOrBias &&
6627117f1b4Smrg       !zoom &&
6637117f1b4Smrg       ctx->Depth.Mask &&
6647117f1b4Smrg       (stencilMask & 0xff) == 0xff) {
665af69d88dSmrg      fast_draw_depth_stencil(ctx, x, y, width, height,
666af69d88dSmrg                              &clippedUnpack, pixels);
6677117f1b4Smrg   }
6687117f1b4Smrg   else {
6697117f1b4Smrg      /* sub-optimal cases:
6707117f1b4Smrg       * Separate depth/stencil buffers, or pixel transfer ops required.
6717117f1b4Smrg       */
6727117f1b4Smrg      /* XXX need to handle very wide images (skippixels) */
673af69d88dSmrg      GLuint *zValues;  /* 32-bit Z values */
6747117f1b4Smrg      GLint i;
6757117f1b4Smrg
676af69d88dSmrg      zValues = malloc(width * sizeof(GLuint));
677af69d88dSmrg      if (!zValues) {
678af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
679af69d88dSmrg         return;
680af69d88dSmrg      }
6817117f1b4Smrg
6827117f1b4Smrg      for (i = 0; i < height; i++) {
6837117f1b4Smrg         const GLuint *depthStencilSrc = (const GLuint *)
6847117f1b4Smrg            _mesa_image_address2d(&clippedUnpack, pixels, width, height,
6857117f1b4Smrg                                  GL_DEPTH_STENCIL_EXT, type, i, 0);
6867117f1b4Smrg
6877117f1b4Smrg         if (ctx->Depth.Mask) {
688af69d88dSmrg            _mesa_unpack_depth_span(ctx, width,
689af69d88dSmrg                                    GL_UNSIGNED_INT, /* dest type */
690af69d88dSmrg                                    zValues,         /* dest addr */
691af69d88dSmrg                                    0xffffffff,      /* depth max */
692af69d88dSmrg                                    type,            /* src type */
693af69d88dSmrg                                    depthStencilSrc, /* src addr */
694af69d88dSmrg                                    &clippedUnpack);
695af69d88dSmrg            if (zoom) {
696af69d88dSmrg               _swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x,
697af69d88dSmrg                                           y + i, zValues);
6987117f1b4Smrg            }
6997117f1b4Smrg            else {
700af69d88dSmrg               GLubyte *dst = _swrast_pixel_address(depthRb, x, y + i);
701af69d88dSmrg               _mesa_pack_uint_z_row(depthRb->Format, width, zValues, dst);
7027117f1b4Smrg            }
7037117f1b4Smrg         }
7047117f1b4Smrg
7057117f1b4Smrg         if (stencilMask != 0x0) {
706af69d88dSmrg            GLubyte *stencilValues = (GLubyte *) zValues; /* re-use buffer */
7077117f1b4Smrg            /* get stencil values, with shift/offset/mapping */
7087117f1b4Smrg            _mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues,
7097117f1b4Smrg                                      type, depthStencilSrc, &clippedUnpack,
7107117f1b4Smrg                                      ctx->_ImageTransferState);
7117117f1b4Smrg            if (zoom)
7127117f1b4Smrg               _swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width,
7137117f1b4Smrg                                                  x, y + i, stencilValues);
7147117f1b4Smrg            else
7157117f1b4Smrg               _swrast_write_stencil_span(ctx, width, x, y + i, stencilValues);
7167117f1b4Smrg         }
7177117f1b4Smrg      }
718af69d88dSmrg
719af69d88dSmrg      free(zValues);
7207117f1b4Smrg   }
7217117f1b4Smrg}
7227117f1b4Smrg
7237117f1b4Smrg
7247117f1b4Smrg/**
7257117f1b4Smrg * Execute software-based glDrawPixels.
7267117f1b4Smrg * By time we get here, all error checking will have been done.
7277117f1b4Smrg */
7287117f1b4Smrgvoid
7293464ebd5Sriastradh_swrast_DrawPixels( struct gl_context *ctx,
7307117f1b4Smrg		    GLint x, GLint y,
7317117f1b4Smrg		    GLsizei width, GLsizei height,
7327117f1b4Smrg		    GLenum format, GLenum type,
7337117f1b4Smrg		    const struct gl_pixelstore_attrib *unpack,
7347117f1b4Smrg		    const GLvoid *pixels )
7357117f1b4Smrg{
7367117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
7374a49301eSmrg   GLboolean save_vp_override = ctx->VertexProgram._Overriden;
7384a49301eSmrg
739cdc920a0Smrg   if (!_mesa_check_conditional_render(ctx))
740cdc920a0Smrg      return; /* don't draw */
741cdc920a0Smrg
7424a49301eSmrg   /* We are creating fragments directly, without going through vertex
7434a49301eSmrg    * programs.
7444a49301eSmrg    *
7454a49301eSmrg    * This override flag tells the fragment processing code that its input
7464a49301eSmrg    * comes from a non-standard source, and it may therefore not rely on
7474a49301eSmrg    * optimizations that assume e.g. constant color if there is no color
7484a49301eSmrg    * vertex array.
7494a49301eSmrg    */
7504a49301eSmrg   _mesa_set_vp_override(ctx, GL_TRUE);
7517117f1b4Smrg
7527117f1b4Smrg   if (ctx->NewState)
7537117f1b4Smrg      _mesa_update_state(ctx);
7547117f1b4Smrg
7557117f1b4Smrg   if (swrast->NewState)
7567117f1b4Smrg      _swrast_validate_derived( ctx );
7577117f1b4Smrg
7583464ebd5Sriastradh   pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
7593464ebd5Sriastradh   if (!pixels) {
7603464ebd5Sriastradh      _mesa_set_vp_override(ctx, save_vp_override);
7613464ebd5Sriastradh      return;
7623464ebd5Sriastradh   }
7637117f1b4Smrg
7643464ebd5Sriastradh   /*
7653464ebd5Sriastradh    * By time we get here, all error checking should have been done.
7663464ebd5Sriastradh    */
7677117f1b4Smrg   switch (format) {
7687117f1b4Smrg   case GL_STENCIL_INDEX:
769af69d88dSmrg      swrast_render_start(ctx);
7707117f1b4Smrg      draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
771af69d88dSmrg      swrast_render_finish(ctx);
7727117f1b4Smrg      break;
7737117f1b4Smrg   case GL_DEPTH_COMPONENT:
774af69d88dSmrg      swrast_render_start(ctx);
7757117f1b4Smrg      draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
776af69d88dSmrg      swrast_render_finish(ctx);
7777117f1b4Smrg      break;
7787117f1b4Smrg   case GL_DEPTH_STENCIL_EXT:
779af69d88dSmrg      swrast_render_start(ctx);
7803464ebd5Sriastradh      draw_depth_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
781af69d88dSmrg      swrast_render_finish(ctx);
7827117f1b4Smrg      break;
7837117f1b4Smrg   default:
7843464ebd5Sriastradh      /* all other formats should be color formats */
7853464ebd5Sriastradh      draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
7867117f1b4Smrg   }
7877117f1b4Smrg
7884a49301eSmrg   _mesa_set_vp_override(ctx, save_vp_override);
7897117f1b4Smrg
7904a49301eSmrg   _mesa_unmap_pbo_source(ctx, unpack);
7917117f1b4Smrg}
792