/** * Zoom/write 32-bit Z values. * No per-fragment operations are applied. */ void _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY, GLint width, GLint spanX, GLint spanY, const GLuint *zVals) { struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; GLuint zoomedVals[MAX_WIDTH]; GLint x0, x1, y0, y1, y; GLint i, zoomedWidth; if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, &x0, &x1, &y0, &y1)) { return; /* totally clipped */ } zoomedWidth = x1 - x0; ASSERT(zoomedWidth > 0); ASSERT(zoomedWidth <= MAX_WIDTH); /* zoom the span horizontally */ for (i = 0; i < zoomedWidth; i++) { GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; ASSERT(j >= 0); ASSERT(j < width); zoomedVals[i] = zVals[j]; } /* write the zoomed spans */ for (y = y0; y < y1; y++) { GLubyte *dst = _swrast_pixel_address(rb, x0, y); _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst); } }
/** * 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); } }