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