/** * Get colors at x/y positions with clipping. * \param type type of values to return */ static void get_values(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, const GLint x[], const GLint y[], void *values, GLenum type) { GLuint i; for (i = 0; i < count; i++) { if (x[i] >= 0 && y[i] >= 0 && x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) { /* inside */ const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]); if (type == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, 1, src, (GLubyte (*)[4]) values + i); } else if (type == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, 1, src, (GLfloat (*)[4]) values + i); } else { _mesa_problem(ctx, "unexpected type in get_values()"); } } } }
/** * Get row of colors with clipping. * \param type type of values to return */ static void get_row(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint count, GLint x, GLint y, GLvoid *values, GLenum type) { GLint skip = 0; GLubyte *src; if (y < 0 || y >= (GLint) rb->Height) return; /* above or below */ if (x + (GLint) count <= 0 || x >= (GLint) rb->Width) return; /* entirely left or right */ if (x + count > rb->Width) { /* right clip */ GLint clip = x + count - rb->Width; count -= clip; } if (x < 0) { /* left clip */ skip = -x; x = 0; count -= skip; } src = _swrast_pixel_address(rb, x, y); if (type == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, count, src, (GLubyte (*)[4]) values + skip); } else if (type == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, count, src, (GLfloat (*)[4]) values + skip); } else { _mesa_problem(ctx, "unexpected type in get_row()"); } }
/** * Read float RGBA pixels from a renderbuffer. Clipping will be done to * prevent reading ouside the buffer's boundaries. * \param rgba the returned colors */ void _swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, GLvoid *rgba) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); GLenum dstType = GL_FLOAT; const GLint bufWidth = (GLint) rb->Width; const GLint bufHeight = (GLint) rb->Height; if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) { /* completely above, below, or right */ /* XXX maybe leave rgba values undefined? */ memset(rgba, 0, 4 * n * sizeof(GLchan)); } else { GLint skip, length; GLubyte *src; if (x < 0) { /* left edge clipping */ skip = -x; length = (GLint) n - skip; if (length < 0) { /* completely left of window */ return; } if (length > bufWidth) { length = bufWidth; } } else if ((GLint) (x + n) > bufWidth) { /* right edge clipping */ skip = 0; length = bufWidth - x; if (length < 0) { /* completely to right of window */ return; } } else { /* no clipping */ skip = 0; length = (GLint) n; } ASSERT(rb); ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB || rb->_BaseFormat == GL_RG || rb->_BaseFormat == GL_RED || rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY || rb->_BaseFormat == GL_LUMINANCE_ALPHA || rb->_BaseFormat == GL_ALPHA); assert(srb->Map); src = _swrast_pixel_address(rb, x + skip, y); if (dstType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(rb->Format, length, src, (GLubyte (*)[4]) rgba + skip); } else if (dstType == GL_FLOAT) { _mesa_unpack_rgba_row(rb->Format, length, src, (GLfloat (*)[4]) rgba + skip); } else { _mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()"); } } }
/** * Bilinear filtered blit (color only, non-integer values). */ static void blit_linear(struct gl_context *ctx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) { struct gl_renderbuffer *readRb = ctx->ReadBuffer->_ColorReadBuffer; struct gl_renderbuffer *drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0]; 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 GLfloat dstHeightF = (GLfloat) dstHeight; 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); GLint dstRow; GLint pixelSize; GLvoid *srcBuffer0, *srcBuffer1; GLint srcBufferY0 = -1, srcBufferY1 = -1; GLvoid *dstBuffer; gl_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); gl_format drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); GLuint bpp = _mesa_get_format_bytes(readFormat); GLenum pixelType; GLubyte *srcMap, *dstMap; GLint srcRowStride, dstRowStride; /* Determine datatype for resampling */ if (_mesa_get_format_max_bits(readFormat) == 8 && _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { pixelType = GL_UNSIGNED_BYTE; pixelSize = 4 * sizeof(GLubyte); } else { pixelType = GL_FLOAT; pixelSize = 4 * sizeof(GLfloat); } /* Allocate the src/dst row buffers. * Keep two adjacent src rows around for bilinear sampling. */ srcBuffer0 = malloc(pixelSize * srcWidth); if (!srcBuffer0) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } srcBuffer1 = malloc(pixelSize * srcWidth); if (!srcBuffer1) { free(srcBuffer0); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } dstBuffer = malloc(pixelSize * dstWidth); if (!dstBuffer) { free(srcBuffer0); free(srcBuffer1); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBufferEXT"); return; } /* * Map src / dst renderbuffers */ if (readRb == drawRb) { /* map whole buffer for read/write */ ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, readRb->Width, readRb->Height, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, &srcMap, &srcRowStride); if (!srcMap) { free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } dstMap = srcMap; dstRowStride = srcRowStride; } else { /* different src/dst buffers */ /* XXX with a bit of work we could just map the regions to be * read/written instead of the whole buffers. */ ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, readRb->Width, readRb->Height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (!srcMap) { free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } ctx->Driver.MapRenderbuffer(ctx, drawRb, 0, 0, drawRb->Width, drawRb->Height, GL_MAP_WRITE_BIT, &dstMap, &dstRowStride); if (!dstMap) { ctx->Driver.UnmapRenderbuffer(ctx, readRb); free(srcBuffer0); free(srcBuffer1); free(dstBuffer); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); return; } } for (dstRow = 0; dstRow < dstHeight; dstRow++) { const GLint dstY = dstYpos + dstRow; const GLfloat srcRow = (dstRow * srcHeight) / dstHeightF; GLint srcRow0 = IFLOOR(srcRow); GLint srcRow1 = srcRow0 + 1; GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ ASSERT(srcRow >= 0); ASSERT(srcRow < srcHeight); if (srcRow1 == srcHeight) { /* last row fudge */ srcRow1 = srcRow0; rowWeight = 0.0; } if (invertY) { srcRow0 = srcHeight - 1 - srcRow0; srcRow1 = srcHeight - 1 - srcRow1; } srcY0 = srcYpos + srcRow0; srcY1 = srcYpos + srcRow1; /* get the two source rows */ if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { /* use same source row buffers again */ } else if (srcY0 == srcBufferY1) { /* move buffer1 into buffer0 by swapping pointers */ GLvoid *tmp = srcBuffer0; srcBuffer0 = srcBuffer1; srcBuffer1 = tmp; /* get y1 row */ { GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src, srcBuffer1); } else { _mesa_unpack_rgba_row(readFormat, srcWidth, src, srcBuffer1); } } srcBufferY0 = srcY0; srcBufferY1 = srcY1; } else { /* get both new rows */ { GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src0, srcBuffer0); _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, src1, srcBuffer1); } else { _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); } } srcBufferY0 = srcY0; srcBufferY1 = srcY1; } if (pixelType == GL_UNSIGNED_BYTE) { resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, dstBuffer, invertX, rowWeight); } else { resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, dstBuffer, invertX, rowWeight); } /* store pixel row in destination */ { GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; if (pixelType == GL_UNSIGNED_BYTE) { _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); } else { _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); } } } free(srcBuffer0); free(srcBuffer1); free(dstBuffer); ctx->Driver.UnmapRenderbuffer(ctx, readRb); if (drawRb != readRb) { ctx->Driver.UnmapRenderbuffer(ctx, drawRb); } }