/** * Apply depth (Z) buffer testing to the span. * \return approx number of pixels that passed (only zero is reliable) */ GLuint _swrast_depth_test_span(struct gl_context *ctx, SWspan *span) { struct gl_framebuffer *fb = ctx->DrawBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; const GLint bpp = _mesa_get_format_bytes(rb->Format); void *zStart; const GLuint count = span->end; const GLuint *fragZ = span->array->z; GLubyte *mask = span->array->mask; void *zBufferVals; GLuint *zBufferTemp = NULL; GLuint passed; GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS); GLboolean ztest16 = GL_FALSE; if (span->arrayMask & SPAN_XY) zStart = NULL; else zStart = _swrast_pixel_address(rb, span->x, span->y); if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 16-bit Z values */ zBufferVals = zStart; ztest16 = GL_TRUE; } else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) { /* directly read/write row of 32-bit Z values */ zBufferVals = zStart; } else { if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) { _mesa_problem(ctx, "Incorrectly writing swrast's integer depth " "values to %s depth buffer", _mesa_get_format_name(rb->Format)); } /* copy Z buffer values into temp buffer (32-bit Z values) */ zBufferTemp = malloc(count * sizeof(GLuint)); if (!zBufferTemp) return 0; if (span->arrayMask & SPAN_XY) { get_z32_values(ctx, rb, count, span->array->x, span->array->y, zBufferTemp); } else { _mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp); } if (zBits == 24) { GLuint i; /* Convert depth buffer values from 32 to 24 bits to match the * fragment Z values generated by rasterization. */ for (i = 0; i < count; i++) { zBufferTemp[i] >>= 8; } } else if (zBits == 16) {
/** * Get array of 32-bit z values from the depth buffer. With clipping. * Note: the returned values are always in the range [0, 2^32-1]. */ static void get_z32_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], GLuint zbuffer[]) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); const GLint w = rb->Width, h = rb->Height; const GLubyte *map = _swrast_pixel_address(rb, 0, 0); GLuint i; if (rb->Format == MESA_FORMAT_Z_UNORM32) { const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { zbuffer[i] = *((GLuint *) (map + y[i] * rowStride + x[i] * 4)); } } } else { const GLint bpp = _mesa_get_format_bytes(rb->Format); const GLint rowStride = srb->RowStride; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) { const GLubyte *src = map + y[i] * rowStride+ x[i] * bpp; _mesa_unpack_uint_z_row(rb->Format, 1, src, &zbuffer[i]); } } } }
/** * For non-float-depth and stencil buffers being read as 24/8 depth/stencil, * copy the integer data directly instead of converting depth to float and * re-packing. */ static GLboolean fast_read_depth_stencil_pixels_separate(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, uint32_t *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer; GLubyte *depthMap, *stencilMap, *stencilVals; int depthStride, stencilStride, i, j; if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height, GL_MAP_READ_BIT, &depthMap, &depthStride); if (!depthMap) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height, GL_MAP_READ_BIT, &stencilMap, &stencilStride); if (!stencilMap) { ctx->Driver.UnmapRenderbuffer(ctx, depthRb); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } stencilVals = malloc(width * sizeof(GLubyte)); if (stencilVals) { for (j = 0; j < height; j++) { _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst); _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width, stencilMap, stencilVals); for (i = 0; i < width; i++) { dst[i] = (dst[i] & 0xffffff00) | stencilVals[i]; } depthMap += depthStride; stencilMap += stencilStride; dst += dstStride / 4; } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); } free(stencilVals); ctx->Driver.UnmapRenderbuffer(ctx, depthRb); ctx->Driver.UnmapRenderbuffer(ctx, stencilRb); return GL_TRUE; }
/** * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the * mapping. */ static GLboolean fast_read_depth_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; GLubyte *map, *dst; int stride, dstStride, j; if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0) return GL_FALSE; if (packing->SwapBytes) return GL_FALSE; if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) return GL_FALSE; if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) || type == GL_UNSIGNED_INT)) return GL_FALSE; ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return GL_TRUE; /* don't bother trying the slow path */ } dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, GL_DEPTH_COMPONENT, type, 0, 0); for (j = 0; j < height; j++) { if (type == GL_UNSIGNED_INT) { _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst); } else { ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16); memcpy(dst, map, width * 2); } map += stride; dst += dstStride; } ctx->Driver.UnmapRenderbuffer(ctx, rb); return GL_TRUE; }
/** * Blit color, depth or stencil with GL_NEAREST filtering. */ static void blit_nearest(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield buffer) { struct gl_renderbuffer *readRb, *drawRb; const GLint srcWidth = ABS(srcX1 - srcX0); const GLint dstWidth = ABS(dstX1 - dstX0); const GLint srcHeight = ABS(srcY1 - srcY0); const GLint dstHeight = ABS(dstY1 - dstY0); const GLint srcXpos = MIN2(srcX0, srcX1); const GLint srcYpos = MIN2(srcY0, srcY1); const GLint dstXpos = MIN2(dstX0, dstX1); const GLint dstYpos = MIN2(dstY0, dstY1); const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); enum mode { DIRECT, UNPACK_RGBA_FLOAT, UNPACK_Z_FLOAT, UNPACK_Z_INT, UNPACK_S, } mode; GLubyte *srcMap, *dstMap; GLint srcRowStride, dstRowStride; GLint dstRow; GLint pixelSize; GLvoid *srcBuffer, *dstBuffer; GLint prevY = -1; typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, const GLvoid *srcBuffer, GLvoid *dstBuffer, GLboolean flip); resample_func resampleRow; switch (buffer) { case GL_COLOR_BUFFER_BIT: readRb = ctx->ReadBuffer->_ColorReadBuffer; drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; if (readRb->Format == drawRb->Format) { mode = DIRECT; pixelSize = _mesa_get_format_bytes(readRb->Format); } else { mode = UNPACK_RGBA_FLOAT; pixelSize = 16; } break; case GL_DEPTH_BUFFER_BIT: readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; /* Note that for depth/stencil, the formats of src/dst must match. By * using the core helpers for pack/unpack, we avoid needing to handle * masking for things like DEPTH copies of Z24S8. */ if (readRb->Format == MESA_FORMAT_Z32_FLOAT || readRb->Format == MESA_FORMAT_Z32_FLOAT_X24S8) { mode = UNPACK_Z_FLOAT; } else { mode = UNPACK_Z_INT; } pixelSize = 4; break; case GL_STENCIL_BUFFER_BIT: readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; mode = UNPACK_S; pixelSize = 1; break; default: _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); return; } /* choose row resampler */ switch (pixelSize) { case 1: resampleRow = resample_row_1; break; case 2: resampleRow = resample_row_2; break; case 4: resampleRow = resample_row_4; break; case 8: resampleRow = resample_row_8; break; case 16: resampleRow = resample_row_16; break; default: _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", pixelSize); return; } if (readRb == drawRb) { /* map whole buffer for read/write */ /* XXX we could be clever and just map the union region of the * source and dest rects. */ GLubyte *map; GLint rowStride; GLint formatSize = _mesa_get_format_bytes(readRb->Format); ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, readRb->Width, readRb->Height, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, &map, &rowStride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } srcMap = map + srcYpos * rowStride + srcXpos * formatSize; dstMap = map + dstYpos * rowStride + dstXpos * formatSize; /* this handles overlapping copies */ if (srcY0 < dstY0) { /* copy in reverse (top->down) order */ srcMap += rowStride * (readRb->Height - 1); dstMap += rowStride * (readRb->Height - 1); srcRowStride = -rowStride; dstRowStride = -rowStride; } else { /* copy in normal (bottom->up) order */ srcRowStride = rowStride; dstRowStride = rowStride; } } else { /* different src/dst buffers */ ctx->Driver.MapRenderbuffer(ctx, readRb, srcXpos, srcYpos, srcWidth, srcHeight, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (!srcMap) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } ctx->Driver.MapRenderbuffer(ctx, drawRb, dstXpos, dstYpos, dstWidth, dstHeight, GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); if (!dstMap) { ctx->Driver.UnmapRenderbuffer(ctx, readRb); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } } /* allocate the src/dst row buffers */ srcBuffer = malloc(pixelSize * srcWidth); if (!srcBuffer) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } dstBuffer = malloc(pixelSize * dstWidth); if (!dstBuffer) { free(srcBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } for (dstRow = 0; dstRow < dstHeight; dstRow++) { GLint srcRow = (dstRow * srcHeight) / dstHeight; GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; ASSERT(srcRow >= 0); ASSERT(srcRow < srcHeight); if (invertY) { srcRow = srcHeight - 1 - srcRow; } /* get pixel row from source and resample to match dest width */ if (prevY != srcRow) { GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; switch (mode) { case DIRECT: memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); break; case UNPACK_RGBA_FLOAT: _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, srcBuffer); break; case UNPACK_Z_FLOAT: _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, srcBuffer); break; case UNPACK_Z_INT: _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, srcBuffer); break; case UNPACK_S: _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, srcRowStart, srcBuffer); break; } (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); prevY = srcRow; } /* store pixel row in destination */ switch (mode) { case DIRECT: memcpy(dstRowStart, dstBuffer, pixelSize * srcWidth); break; case UNPACK_RGBA_FLOAT: _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, dstRowStart); break; case UNPACK_Z_FLOAT: _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, dstRowStart); break; case UNPACK_Z_INT: _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, dstRowStart); break; case UNPACK_S: _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, dstRowStart); break; } } free(srcBuffer); free(dstBuffer); ctx->Driver.UnmapRenderbuffer(ctx, readRb); if (drawRb != readRb) { ctx->Driver.UnmapRenderbuffer(ctx, drawRb); } }