1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg#include "main/glheader.h" 27848b8605Smrg#include "main/condrender.h" 28848b8605Smrg#include "main/image.h" 29848b8605Smrg#include "main/macros.h" 30848b8605Smrg#include "main/format_unpack.h" 31848b8605Smrg#include "main/format_pack.h" 32848b8605Smrg#include "main/condrender.h" 33848b8605Smrg#include "s_context.h" 34848b8605Smrg 35848b8605Smrg 36848b8605Smrg#define ABS(X) ((X) < 0 ? -(X) : (X)) 37848b8605Smrg 38848b8605Smrg 39848b8605Smrg/** 40848b8605Smrg * Generate a row resampler function for GL_NEAREST mode. 41848b8605Smrg */ 42848b8605Smrg#define RESAMPLE(NAME, PIXELTYPE, SIZE) \ 43848b8605Smrgstatic void \ 44848b8605SmrgNAME(GLint srcWidth, GLint dstWidth, \ 45848b8605Smrg const GLvoid *srcBuffer, GLvoid *dstBuffer, \ 46848b8605Smrg GLboolean flip) \ 47848b8605Smrg{ \ 48848b8605Smrg const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\ 49848b8605Smrg PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \ 50848b8605Smrg GLint dstCol; \ 51848b8605Smrg \ 52848b8605Smrg if (flip) { \ 53848b8605Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 54848b8605Smrg GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 55b8e80941Smrg assert(srcCol >= 0); \ 56b8e80941Smrg assert(srcCol < srcWidth); \ 57848b8605Smrg srcCol = srcWidth - 1 - srcCol; /* flip */ \ 58848b8605Smrg if (SIZE == 1) { \ 59848b8605Smrg dst[dstCol] = src[srcCol]; \ 60848b8605Smrg } \ 61848b8605Smrg else if (SIZE == 2) { \ 62848b8605Smrg dst[dstCol*2+0] = src[srcCol*2+0]; \ 63848b8605Smrg dst[dstCol*2+1] = src[srcCol*2+1]; \ 64848b8605Smrg } \ 65848b8605Smrg else if (SIZE == 4) { \ 66848b8605Smrg dst[dstCol*4+0] = src[srcCol*4+0]; \ 67848b8605Smrg dst[dstCol*4+1] = src[srcCol*4+1]; \ 68848b8605Smrg dst[dstCol*4+2] = src[srcCol*4+2]; \ 69848b8605Smrg dst[dstCol*4+3] = src[srcCol*4+3]; \ 70848b8605Smrg } \ 71848b8605Smrg } \ 72848b8605Smrg } \ 73848b8605Smrg else { \ 74848b8605Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { \ 75848b8605Smrg GLint srcCol = (dstCol * srcWidth) / dstWidth; \ 76b8e80941Smrg assert(srcCol >= 0); \ 77b8e80941Smrg assert(srcCol < srcWidth); \ 78848b8605Smrg if (SIZE == 1) { \ 79848b8605Smrg dst[dstCol] = src[srcCol]; \ 80848b8605Smrg } \ 81848b8605Smrg else if (SIZE == 2) { \ 82848b8605Smrg dst[dstCol*2+0] = src[srcCol*2+0]; \ 83848b8605Smrg dst[dstCol*2+1] = src[srcCol*2+1]; \ 84848b8605Smrg } \ 85848b8605Smrg else if (SIZE == 4) { \ 86848b8605Smrg dst[dstCol*4+0] = src[srcCol*4+0]; \ 87848b8605Smrg dst[dstCol*4+1] = src[srcCol*4+1]; \ 88848b8605Smrg dst[dstCol*4+2] = src[srcCol*4+2]; \ 89848b8605Smrg dst[dstCol*4+3] = src[srcCol*4+3]; \ 90848b8605Smrg } \ 91848b8605Smrg } \ 92848b8605Smrg } \ 93848b8605Smrg} 94848b8605Smrg 95848b8605Smrg/** 96848b8605Smrg * Resamplers for 1, 2, 4, 8 and 16-byte pixels. 97848b8605Smrg */ 98848b8605SmrgRESAMPLE(resample_row_1, GLubyte, 1) 99848b8605SmrgRESAMPLE(resample_row_2, GLushort, 1) 100848b8605SmrgRESAMPLE(resample_row_4, GLuint, 1) 101848b8605SmrgRESAMPLE(resample_row_8, GLuint, 2) 102848b8605SmrgRESAMPLE(resample_row_16, GLuint, 4) 103848b8605Smrg 104848b8605Smrg 105848b8605Smrg/** 106848b8605Smrg * Blit color, depth or stencil with GL_NEAREST filtering. 107848b8605Smrg */ 108848b8605Smrgstatic void 109848b8605Smrgblit_nearest(struct gl_context *ctx, 110b8e80941Smrg struct gl_framebuffer *readFb, 111b8e80941Smrg struct gl_framebuffer *drawFb, 112848b8605Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 113848b8605Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 114848b8605Smrg GLbitfield buffer) 115848b8605Smrg{ 116848b8605Smrg struct gl_renderbuffer *readRb, *drawRb = NULL; 117848b8605Smrg struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL; 118848b8605Smrg GLuint numDrawBuffers = 0; 119848b8605Smrg GLuint i; 120848b8605Smrg 121848b8605Smrg const GLint srcWidth = ABS(srcX1 - srcX0); 122848b8605Smrg const GLint dstWidth = ABS(dstX1 - dstX0); 123848b8605Smrg const GLint srcHeight = ABS(srcY1 - srcY0); 124848b8605Smrg const GLint dstHeight = ABS(dstY1 - dstY0); 125848b8605Smrg 126848b8605Smrg const GLint srcXpos = MIN2(srcX0, srcX1); 127848b8605Smrg const GLint srcYpos = MIN2(srcY0, srcY1); 128848b8605Smrg const GLint dstXpos = MIN2(dstX0, dstX1); 129848b8605Smrg const GLint dstYpos = MIN2(dstY0, dstY1); 130848b8605Smrg 131848b8605Smrg const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 132848b8605Smrg const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 133848b8605Smrg enum mode { 134848b8605Smrg DIRECT, 135848b8605Smrg UNPACK_RGBA_FLOAT, 136848b8605Smrg UNPACK_Z_FLOAT, 137848b8605Smrg UNPACK_Z_INT, 138848b8605Smrg UNPACK_S, 139848b8605Smrg } mode = DIRECT; 140848b8605Smrg GLubyte *srcMap, *dstMap; 141848b8605Smrg GLint srcRowStride, dstRowStride; 142848b8605Smrg GLint dstRow; 143848b8605Smrg 144848b8605Smrg GLint pixelSize = 0; 145848b8605Smrg GLvoid *srcBuffer, *dstBuffer; 146848b8605Smrg GLint prevY = -1; 147848b8605Smrg 148848b8605Smrg typedef void (*resample_func)(GLint srcWidth, GLint dstWidth, 149848b8605Smrg const GLvoid *srcBuffer, GLvoid *dstBuffer, 150848b8605Smrg GLboolean flip); 151848b8605Smrg resample_func resampleRow; 152848b8605Smrg 153848b8605Smrg switch (buffer) { 154848b8605Smrg case GL_COLOR_BUFFER_BIT: 155848b8605Smrg readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex]; 156848b8605Smrg readRb = readFb->_ColorReadBuffer; 157848b8605Smrg numDrawBuffers = drawFb->_NumColorDrawBuffers; 158848b8605Smrg break; 159848b8605Smrg case GL_DEPTH_BUFFER_BIT: 160848b8605Smrg readAtt = &readFb->Attachment[BUFFER_DEPTH]; 161848b8605Smrg drawAtt = &drawFb->Attachment[BUFFER_DEPTH]; 162848b8605Smrg readRb = readAtt->Renderbuffer; 163848b8605Smrg drawRb = drawAtt->Renderbuffer; 164848b8605Smrg numDrawBuffers = 1; 165848b8605Smrg 166848b8605Smrg /* Note that for depth/stencil, the formats of src/dst must match. By 167848b8605Smrg * using the core helpers for pack/unpack, we avoid needing to handle 168848b8605Smrg * masking for things like DEPTH copies of Z24S8. 169848b8605Smrg */ 170848b8605Smrg if (readRb->Format == MESA_FORMAT_Z_FLOAT32 || 171848b8605Smrg readRb->Format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) { 172848b8605Smrg mode = UNPACK_Z_FLOAT; 173848b8605Smrg } else { 174848b8605Smrg mode = UNPACK_Z_INT; 175848b8605Smrg } 176848b8605Smrg pixelSize = 4; 177848b8605Smrg break; 178848b8605Smrg case GL_STENCIL_BUFFER_BIT: 179848b8605Smrg readAtt = &readFb->Attachment[BUFFER_STENCIL]; 180848b8605Smrg drawAtt = &drawFb->Attachment[BUFFER_STENCIL]; 181848b8605Smrg readRb = readAtt->Renderbuffer; 182848b8605Smrg drawRb = drawAtt->Renderbuffer; 183848b8605Smrg numDrawBuffers = 1; 184848b8605Smrg mode = UNPACK_S; 185848b8605Smrg pixelSize = 1; 186848b8605Smrg break; 187848b8605Smrg default: 188848b8605Smrg _mesa_problem(ctx, "unexpected buffer in blit_nearest()"); 189848b8605Smrg return; 190848b8605Smrg } 191848b8605Smrg 192848b8605Smrg /* allocate the src/dst row buffers */ 193848b8605Smrg srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth); 194848b8605Smrg dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth); 195848b8605Smrg if (!srcBuffer || !dstBuffer) 196848b8605Smrg goto fail_no_memory; 197848b8605Smrg 198848b8605Smrg /* Blit to all the draw buffers */ 199848b8605Smrg for (i = 0; i < numDrawBuffers; i++) { 200848b8605Smrg if (buffer == GL_COLOR_BUFFER_BIT) { 201b8e80941Smrg gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 202b8e80941Smrg if (idx == BUFFER_NONE) 203848b8605Smrg continue; 204848b8605Smrg drawAtt = &drawFb->Attachment[idx]; 205848b8605Smrg drawRb = drawAtt->Renderbuffer; 206848b8605Smrg 207848b8605Smrg if (!drawRb) 208848b8605Smrg continue; 209848b8605Smrg 210848b8605Smrg if (readRb->Format == drawRb->Format) { 211848b8605Smrg mode = DIRECT; 212848b8605Smrg pixelSize = _mesa_get_format_bytes(readRb->Format); 213848b8605Smrg } else { 214848b8605Smrg mode = UNPACK_RGBA_FLOAT; 215848b8605Smrg pixelSize = 16; 216848b8605Smrg } 217848b8605Smrg } 218848b8605Smrg 219848b8605Smrg /* choose row resampler */ 220848b8605Smrg switch (pixelSize) { 221848b8605Smrg case 1: 222848b8605Smrg resampleRow = resample_row_1; 223848b8605Smrg break; 224848b8605Smrg case 2: 225848b8605Smrg resampleRow = resample_row_2; 226848b8605Smrg break; 227848b8605Smrg case 4: 228848b8605Smrg resampleRow = resample_row_4; 229848b8605Smrg break; 230848b8605Smrg case 8: 231848b8605Smrg resampleRow = resample_row_8; 232848b8605Smrg break; 233848b8605Smrg case 16: 234848b8605Smrg resampleRow = resample_row_16; 235848b8605Smrg break; 236848b8605Smrg default: 237848b8605Smrg _mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest", 238848b8605Smrg pixelSize); 239848b8605Smrg goto fail; 240848b8605Smrg } 241848b8605Smrg 242848b8605Smrg if ((readRb == drawRb) || 243848b8605Smrg (readAtt->Texture && drawAtt->Texture && 244848b8605Smrg (readAtt->Texture == drawAtt->Texture))) { 245848b8605Smrg /* map whole buffer for read/write */ 246848b8605Smrg /* XXX we could be clever and just map the union region of the 247848b8605Smrg * source and dest rects. 248848b8605Smrg */ 249848b8605Smrg GLubyte *map; 250848b8605Smrg GLint rowStride; 251848b8605Smrg GLint formatSize = _mesa_get_format_bytes(readRb->Format); 252848b8605Smrg 253848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0, 254848b8605Smrg readRb->Width, readRb->Height, 255848b8605Smrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 256b8e80941Smrg &map, &rowStride, readFb->FlipY); 257848b8605Smrg if (!map) { 258848b8605Smrg goto fail_no_memory; 259848b8605Smrg } 260848b8605Smrg 261848b8605Smrg srcMap = map + srcYpos * rowStride + srcXpos * formatSize; 262848b8605Smrg dstMap = map + dstYpos * rowStride + dstXpos * formatSize; 263848b8605Smrg 264848b8605Smrg /* this handles overlapping copies */ 265848b8605Smrg if (srcY0 < dstY0) { 266848b8605Smrg /* copy in reverse (top->down) order */ 267848b8605Smrg srcMap += rowStride * (readRb->Height - 1); 268848b8605Smrg dstMap += rowStride * (readRb->Height - 1); 269848b8605Smrg srcRowStride = -rowStride; 270848b8605Smrg dstRowStride = -rowStride; 271848b8605Smrg } 272848b8605Smrg else { 273848b8605Smrg /* copy in normal (bottom->up) order */ 274848b8605Smrg srcRowStride = rowStride; 275848b8605Smrg dstRowStride = rowStride; 276848b8605Smrg } 277848b8605Smrg } 278848b8605Smrg else { 279848b8605Smrg /* different src/dst buffers */ 280848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, readRb, 281848b8605Smrg srcXpos, srcYpos, 282848b8605Smrg srcWidth, srcHeight, 283b8e80941Smrg GL_MAP_READ_BIT, &srcMap, &srcRowStride, 284b8e80941Smrg readFb->FlipY); 285848b8605Smrg if (!srcMap) { 286848b8605Smrg goto fail_no_memory; 287848b8605Smrg } 288848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, drawRb, 289848b8605Smrg dstXpos, dstYpos, 290848b8605Smrg dstWidth, dstHeight, 291b8e80941Smrg GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 292b8e80941Smrg drawFb->FlipY); 293848b8605Smrg if (!dstMap) { 294848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 295848b8605Smrg goto fail_no_memory; 296848b8605Smrg } 297848b8605Smrg } 298848b8605Smrg 299848b8605Smrg for (dstRow = 0; dstRow < dstHeight; dstRow++) { 300848b8605Smrg GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 301848b8605Smrg GLint srcRow = IROUND(srcRowF); 302848b8605Smrg GLubyte *dstRowStart = dstMap + dstRowStride * dstRow; 303848b8605Smrg 304b8e80941Smrg assert(srcRow >= 0); 305b8e80941Smrg assert(srcRow < srcHeight); 306848b8605Smrg 307848b8605Smrg if (invertY) { 308848b8605Smrg srcRow = srcHeight - 1 - srcRow; 309848b8605Smrg } 310848b8605Smrg 311848b8605Smrg /* get pixel row from source and resample to match dest width */ 312848b8605Smrg if (prevY != srcRow) { 313848b8605Smrg GLubyte *srcRowStart = srcMap + srcRowStride * srcRow; 314848b8605Smrg 315848b8605Smrg switch (mode) { 316848b8605Smrg case DIRECT: 317848b8605Smrg memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth); 318848b8605Smrg break; 319848b8605Smrg case UNPACK_RGBA_FLOAT: 320848b8605Smrg _mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart, 321848b8605Smrg srcBuffer); 322848b8605Smrg break; 323848b8605Smrg case UNPACK_Z_FLOAT: 324848b8605Smrg _mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart, 325848b8605Smrg srcBuffer); 326848b8605Smrg break; 327848b8605Smrg case UNPACK_Z_INT: 328848b8605Smrg _mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart, 329848b8605Smrg srcBuffer); 330848b8605Smrg break; 331848b8605Smrg case UNPACK_S: 332848b8605Smrg _mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth, 333848b8605Smrg srcRowStart, srcBuffer); 334848b8605Smrg break; 335848b8605Smrg } 336848b8605Smrg 337848b8605Smrg (*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX); 338848b8605Smrg prevY = srcRow; 339848b8605Smrg } 340848b8605Smrg 341848b8605Smrg /* store pixel row in destination */ 342848b8605Smrg switch (mode) { 343848b8605Smrg case DIRECT: 344848b8605Smrg memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth); 345848b8605Smrg break; 346848b8605Smrg case UNPACK_RGBA_FLOAT: 347848b8605Smrg _mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer, 348848b8605Smrg dstRowStart); 349848b8605Smrg break; 350848b8605Smrg case UNPACK_Z_FLOAT: 351848b8605Smrg _mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer, 352848b8605Smrg dstRowStart); 353848b8605Smrg break; 354848b8605Smrg case UNPACK_Z_INT: 355848b8605Smrg _mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer, 356848b8605Smrg dstRowStart); 357848b8605Smrg break; 358848b8605Smrg case UNPACK_S: 359848b8605Smrg _mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer, 360848b8605Smrg dstRowStart); 361848b8605Smrg break; 362848b8605Smrg } 363848b8605Smrg } 364848b8605Smrg 365848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 366848b8605Smrg if (drawRb != readRb) { 367848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 368848b8605Smrg } 369848b8605Smrg } 370848b8605Smrg 371848b8605Smrgfail: 372848b8605Smrg free(srcBuffer); 373848b8605Smrg free(dstBuffer); 374848b8605Smrg return; 375848b8605Smrg 376848b8605Smrgfail_no_memory: 377848b8605Smrg free(srcBuffer); 378848b8605Smrg free(dstBuffer); 379848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer"); 380848b8605Smrg} 381848b8605Smrg 382848b8605Smrg 383848b8605Smrg 384848b8605Smrg#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) ) 385848b8605Smrg 386848b8605Smrgstatic inline GLfloat 387848b8605Smrglerp_2d(GLfloat a, GLfloat b, 388848b8605Smrg GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11) 389848b8605Smrg{ 390848b8605Smrg const GLfloat temp0 = LERP(a, v00, v10); 391848b8605Smrg const GLfloat temp1 = LERP(a, v01, v11); 392848b8605Smrg return LERP(b, temp0, temp1); 393848b8605Smrg} 394848b8605Smrg 395848b8605Smrg 396848b8605Smrg/** 397848b8605Smrg * Bilinear interpolation of two source rows. 398848b8605Smrg * GLubyte pixels. 399848b8605Smrg */ 400848b8605Smrgstatic void 401848b8605Smrgresample_linear_row_ub(GLint srcWidth, GLint dstWidth, 402848b8605Smrg const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 403848b8605Smrg GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 404848b8605Smrg{ 405848b8605Smrg const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0; 406848b8605Smrg const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1; 407848b8605Smrg GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer; 408848b8605Smrg GLint dstCol; 409848b8605Smrg 410848b8605Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { 411848b8605Smrg const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 412848b8605Smrg GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); 413848b8605Smrg GLint srcCol1 = srcCol0 + 1; 414848b8605Smrg GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 415848b8605Smrg GLfloat red, green, blue, alpha; 416848b8605Smrg 417b8e80941Smrg assert(srcCol0 < srcWidth); 418b8e80941Smrg assert(srcCol1 <= srcWidth); 419848b8605Smrg 420848b8605Smrg if (srcCol1 == srcWidth) { 421848b8605Smrg /* last column fudge */ 422848b8605Smrg srcCol1--; 423848b8605Smrg colWeight = 0.0; 424848b8605Smrg } 425848b8605Smrg 426848b8605Smrg if (flip) { 427848b8605Smrg srcCol0 = srcWidth - 1 - srcCol0; 428848b8605Smrg srcCol1 = srcWidth - 1 - srcCol1; 429848b8605Smrg } 430848b8605Smrg 431848b8605Smrg red = lerp_2d(colWeight, rowWeight, 432848b8605Smrg srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 433848b8605Smrg srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 434848b8605Smrg green = lerp_2d(colWeight, rowWeight, 435848b8605Smrg srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 436848b8605Smrg srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 437848b8605Smrg blue = lerp_2d(colWeight, rowWeight, 438848b8605Smrg srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 439848b8605Smrg srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 440848b8605Smrg alpha = lerp_2d(colWeight, rowWeight, 441848b8605Smrg srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 442848b8605Smrg srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 443848b8605Smrg 444848b8605Smrg dstColor[dstCol][RCOMP] = IFLOOR(red); 445848b8605Smrg dstColor[dstCol][GCOMP] = IFLOOR(green); 446848b8605Smrg dstColor[dstCol][BCOMP] = IFLOOR(blue); 447848b8605Smrg dstColor[dstCol][ACOMP] = IFLOOR(alpha); 448848b8605Smrg } 449848b8605Smrg} 450848b8605Smrg 451848b8605Smrg 452848b8605Smrg/** 453848b8605Smrg * Bilinear interpolation of two source rows. floating point pixels. 454848b8605Smrg */ 455848b8605Smrgstatic void 456848b8605Smrgresample_linear_row_float(GLint srcWidth, GLint dstWidth, 457848b8605Smrg const GLvoid *srcBuffer0, const GLvoid *srcBuffer1, 458848b8605Smrg GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight) 459848b8605Smrg{ 460848b8605Smrg const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0; 461848b8605Smrg const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1; 462848b8605Smrg GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer; 463848b8605Smrg GLint dstCol; 464848b8605Smrg 465848b8605Smrg for (dstCol = 0; dstCol < dstWidth; dstCol++) { 466848b8605Smrg const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F; 467848b8605Smrg GLint srcCol0 = MAX2(0, IFLOOR(srcCol)); 468848b8605Smrg GLint srcCol1 = srcCol0 + 1; 469848b8605Smrg GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */ 470848b8605Smrg GLfloat red, green, blue, alpha; 471848b8605Smrg 472b8e80941Smrg assert(srcCol0 < srcWidth); 473b8e80941Smrg assert(srcCol1 <= srcWidth); 474848b8605Smrg 475848b8605Smrg if (srcCol1 == srcWidth) { 476848b8605Smrg /* last column fudge */ 477848b8605Smrg srcCol1--; 478848b8605Smrg colWeight = 0.0; 479848b8605Smrg } 480848b8605Smrg 481848b8605Smrg if (flip) { 482848b8605Smrg srcCol0 = srcWidth - 1 - srcCol0; 483848b8605Smrg srcCol1 = srcWidth - 1 - srcCol1; 484848b8605Smrg } 485848b8605Smrg 486848b8605Smrg red = lerp_2d(colWeight, rowWeight, 487848b8605Smrg srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP], 488848b8605Smrg srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]); 489848b8605Smrg green = lerp_2d(colWeight, rowWeight, 490848b8605Smrg srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP], 491848b8605Smrg srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]); 492848b8605Smrg blue = lerp_2d(colWeight, rowWeight, 493848b8605Smrg srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP], 494848b8605Smrg srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]); 495848b8605Smrg alpha = lerp_2d(colWeight, rowWeight, 496848b8605Smrg srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP], 497848b8605Smrg srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]); 498848b8605Smrg 499848b8605Smrg dstColor[dstCol][RCOMP] = red; 500848b8605Smrg dstColor[dstCol][GCOMP] = green; 501848b8605Smrg dstColor[dstCol][BCOMP] = blue; 502848b8605Smrg dstColor[dstCol][ACOMP] = alpha; 503848b8605Smrg } 504848b8605Smrg} 505848b8605Smrg 506848b8605Smrg 507848b8605Smrg 508848b8605Smrg/** 509848b8605Smrg * Bilinear filtered blit (color only, non-integer values). 510848b8605Smrg */ 511848b8605Smrgstatic void 512848b8605Smrgblit_linear(struct gl_context *ctx, 513b8e80941Smrg struct gl_framebuffer *readFb, 514b8e80941Smrg struct gl_framebuffer *drawFb, 515848b8605Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 516848b8605Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1) 517848b8605Smrg{ 518848b8605Smrg struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer; 519848b8605Smrg struct gl_renderbuffer_attachment *readAtt = 520848b8605Smrg &readFb->Attachment[readFb->_ColorReadBufferIndex]; 521848b8605Smrg 522848b8605Smrg const GLint srcWidth = ABS(srcX1 - srcX0); 523848b8605Smrg const GLint dstWidth = ABS(dstX1 - dstX0); 524848b8605Smrg const GLint srcHeight = ABS(srcY1 - srcY0); 525848b8605Smrg const GLint dstHeight = ABS(dstY1 - dstY0); 526848b8605Smrg 527848b8605Smrg const GLint srcXpos = MIN2(srcX0, srcX1); 528848b8605Smrg const GLint srcYpos = MIN2(srcY0, srcY1); 529848b8605Smrg const GLint dstXpos = MIN2(dstX0, dstX1); 530848b8605Smrg const GLint dstYpos = MIN2(dstY0, dstY1); 531848b8605Smrg 532848b8605Smrg const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0); 533848b8605Smrg const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0); 534848b8605Smrg 535848b8605Smrg GLint dstRow; 536848b8605Smrg 537848b8605Smrg GLint pixelSize; 538848b8605Smrg GLvoid *srcBuffer0, *srcBuffer1; 539848b8605Smrg GLint srcBufferY0 = -1, srcBufferY1 = -1; 540848b8605Smrg GLvoid *dstBuffer; 541848b8605Smrg 542848b8605Smrg mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format); 543848b8605Smrg GLuint bpp = _mesa_get_format_bytes(readFormat); 544848b8605Smrg 545848b8605Smrg GLenum pixelType; 546848b8605Smrg 547848b8605Smrg GLubyte *srcMap, *dstMap; 548848b8605Smrg GLint srcRowStride, dstRowStride; 549848b8605Smrg GLuint i; 550848b8605Smrg 551848b8605Smrg 552848b8605Smrg /* Determine datatype for resampling */ 553848b8605Smrg if (_mesa_get_format_max_bits(readFormat) == 8 && 554848b8605Smrg _mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) { 555848b8605Smrg pixelType = GL_UNSIGNED_BYTE; 556848b8605Smrg pixelSize = 4 * sizeof(GLubyte); 557848b8605Smrg } 558848b8605Smrg else { 559848b8605Smrg pixelType = GL_FLOAT; 560848b8605Smrg pixelSize = 4 * sizeof(GLfloat); 561848b8605Smrg } 562848b8605Smrg 563848b8605Smrg /* Allocate the src/dst row buffers. 564848b8605Smrg * Keep two adjacent src rows around for bilinear sampling. 565848b8605Smrg */ 566848b8605Smrg srcBuffer0 = malloc(pixelSize * srcWidth); 567848b8605Smrg srcBuffer1 = malloc(pixelSize * srcWidth); 568848b8605Smrg dstBuffer = malloc(pixelSize * dstWidth); 569848b8605Smrg if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) { 570848b8605Smrg goto fail_no_memory; 571848b8605Smrg } 572848b8605Smrg 573848b8605Smrg for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { 574b8e80941Smrg gl_buffer_index idx = drawFb->_ColorDrawBufferIndexes[i]; 575848b8605Smrg struct gl_renderbuffer_attachment *drawAtt; 576848b8605Smrg struct gl_renderbuffer *drawRb; 577848b8605Smrg mesa_format drawFormat; 578848b8605Smrg 579b8e80941Smrg if (idx == BUFFER_NONE) 580848b8605Smrg continue; 581848b8605Smrg 582848b8605Smrg drawAtt = &drawFb->Attachment[idx]; 583848b8605Smrg drawRb = drawAtt->Renderbuffer; 584848b8605Smrg if (!drawRb) 585848b8605Smrg continue; 586848b8605Smrg 587848b8605Smrg drawFormat = _mesa_get_srgb_format_linear(drawRb->Format); 588848b8605Smrg 589848b8605Smrg /* 590848b8605Smrg * Map src / dst renderbuffers 591848b8605Smrg */ 592848b8605Smrg if ((readRb == drawRb) || 593848b8605Smrg (readAtt->Texture && drawAtt->Texture && 594848b8605Smrg (readAtt->Texture == drawAtt->Texture))) { 595848b8605Smrg /* map whole buffer for read/write */ 596848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, readRb, 597848b8605Smrg 0, 0, readRb->Width, readRb->Height, 598848b8605Smrg GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, 599b8e80941Smrg &srcMap, &srcRowStride, 600b8e80941Smrg readFb->FlipY); 601848b8605Smrg if (!srcMap) { 602848b8605Smrg goto fail_no_memory; 603848b8605Smrg } 604848b8605Smrg 605848b8605Smrg dstMap = srcMap; 606848b8605Smrg dstRowStride = srcRowStride; 607848b8605Smrg } 608848b8605Smrg else { 609848b8605Smrg /* different src/dst buffers */ 610848b8605Smrg /* XXX with a bit of work we could just map the regions to be 611848b8605Smrg * read/written instead of the whole buffers. 612848b8605Smrg */ 613848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, readRb, 614848b8605Smrg 0, 0, readRb->Width, readRb->Height, 615b8e80941Smrg GL_MAP_READ_BIT, &srcMap, &srcRowStride, 616b8e80941Smrg readFb->FlipY); 617848b8605Smrg if (!srcMap) { 618848b8605Smrg goto fail_no_memory; 619848b8605Smrg } 620848b8605Smrg ctx->Driver.MapRenderbuffer(ctx, drawRb, 621848b8605Smrg 0, 0, drawRb->Width, drawRb->Height, 622b8e80941Smrg GL_MAP_WRITE_BIT, &dstMap, &dstRowStride, 623b8e80941Smrg drawFb->FlipY); 624848b8605Smrg if (!dstMap) { 625848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 626848b8605Smrg goto fail_no_memory; 627848b8605Smrg } 628848b8605Smrg } 629848b8605Smrg 630848b8605Smrg for (dstRow = 0; dstRow < dstHeight; dstRow++) { 631848b8605Smrg const GLint dstY = dstYpos + dstRow; 632848b8605Smrg GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F; 633848b8605Smrg GLint srcRow0 = MAX2(0, IFLOOR(srcRow)); 634848b8605Smrg GLint srcRow1 = srcRow0 + 1; 635848b8605Smrg GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */ 636848b8605Smrg 637848b8605Smrg if (srcRow1 == srcHeight) { 638848b8605Smrg /* last row fudge */ 639848b8605Smrg srcRow1 = srcRow0; 640848b8605Smrg rowWeight = 0.0; 641848b8605Smrg } 642848b8605Smrg 643848b8605Smrg if (invertY) { 644848b8605Smrg srcRow0 = srcHeight - 1 - srcRow0; 645848b8605Smrg srcRow1 = srcHeight - 1 - srcRow1; 646848b8605Smrg } 647848b8605Smrg 648848b8605Smrg srcY0 = srcYpos + srcRow0; 649848b8605Smrg srcY1 = srcYpos + srcRow1; 650848b8605Smrg 651848b8605Smrg /* get the two source rows */ 652848b8605Smrg if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) { 653848b8605Smrg /* use same source row buffers again */ 654848b8605Smrg } 655848b8605Smrg else if (srcY0 == srcBufferY1) { 656848b8605Smrg /* move buffer1 into buffer0 by swapping pointers */ 657848b8605Smrg GLvoid *tmp = srcBuffer0; 658848b8605Smrg srcBuffer0 = srcBuffer1; 659848b8605Smrg srcBuffer1 = tmp; 660848b8605Smrg /* get y1 row */ 661848b8605Smrg { 662848b8605Smrg GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 663848b8605Smrg if (pixelType == GL_UNSIGNED_BYTE) { 664848b8605Smrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 665848b8605Smrg src, srcBuffer1); 666848b8605Smrg } 667848b8605Smrg else { 668848b8605Smrg _mesa_unpack_rgba_row(readFormat, srcWidth, 669848b8605Smrg src, srcBuffer1); 670848b8605Smrg } 671848b8605Smrg } 672848b8605Smrg srcBufferY0 = srcY0; 673848b8605Smrg srcBufferY1 = srcY1; 674848b8605Smrg } 675848b8605Smrg else { 676848b8605Smrg /* get both new rows */ 677848b8605Smrg { 678848b8605Smrg GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp; 679848b8605Smrg GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp; 680848b8605Smrg if (pixelType == GL_UNSIGNED_BYTE) { 681848b8605Smrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 682848b8605Smrg src0, srcBuffer0); 683848b8605Smrg _mesa_unpack_ubyte_rgba_row(readFormat, srcWidth, 684848b8605Smrg src1, srcBuffer1); 685848b8605Smrg } 686848b8605Smrg else { 687848b8605Smrg _mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0); 688848b8605Smrg _mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1); 689848b8605Smrg } 690848b8605Smrg } 691848b8605Smrg srcBufferY0 = srcY0; 692848b8605Smrg srcBufferY1 = srcY1; 693848b8605Smrg } 694848b8605Smrg 695848b8605Smrg if (pixelType == GL_UNSIGNED_BYTE) { 696848b8605Smrg resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 697848b8605Smrg dstBuffer, invertX, rowWeight); 698848b8605Smrg } 699848b8605Smrg else { 700848b8605Smrg resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1, 701848b8605Smrg dstBuffer, invertX, rowWeight); 702848b8605Smrg } 703848b8605Smrg 704848b8605Smrg /* store pixel row in destination */ 705848b8605Smrg { 706848b8605Smrg GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp; 707848b8605Smrg if (pixelType == GL_UNSIGNED_BYTE) { 708848b8605Smrg _mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 709848b8605Smrg } 710848b8605Smrg else { 711848b8605Smrg _mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst); 712848b8605Smrg } 713848b8605Smrg } 714848b8605Smrg } 715848b8605Smrg 716848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, readRb); 717848b8605Smrg if (drawRb != readRb) { 718848b8605Smrg ctx->Driver.UnmapRenderbuffer(ctx, drawRb); 719848b8605Smrg } 720848b8605Smrg } 721848b8605Smrg 722848b8605Smrg free(srcBuffer0); 723848b8605Smrg free(srcBuffer1); 724848b8605Smrg free(dstBuffer); 725848b8605Smrg return; 726848b8605Smrg 727848b8605Smrgfail_no_memory: 728848b8605Smrg free(srcBuffer0); 729848b8605Smrg free(srcBuffer1); 730848b8605Smrg free(dstBuffer); 731848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer"); 732848b8605Smrg} 733848b8605Smrg 734848b8605Smrg 735848b8605Smrg 736848b8605Smrg/** 737848b8605Smrg * Software fallback for glBlitFramebufferEXT(). 738848b8605Smrg */ 739848b8605Smrgvoid 740848b8605Smrg_swrast_BlitFramebuffer(struct gl_context *ctx, 741b8e80941Smrg struct gl_framebuffer *readFb, 742b8e80941Smrg struct gl_framebuffer *drawFb, 743848b8605Smrg GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 744848b8605Smrg GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 745848b8605Smrg GLbitfield mask, GLenum filter) 746848b8605Smrg{ 747848b8605Smrg static const GLbitfield buffers[3] = { 748848b8605Smrg GL_COLOR_BUFFER_BIT, 749848b8605Smrg GL_DEPTH_BUFFER_BIT, 750848b8605Smrg GL_STENCIL_BUFFER_BIT 751848b8605Smrg }; 752848b8605Smrg static const GLenum buffer_enums[3] = { 753848b8605Smrg GL_COLOR, 754848b8605Smrg GL_DEPTH, 755848b8605Smrg GL_STENCIL, 756848b8605Smrg }; 757848b8605Smrg GLint i; 758848b8605Smrg 759848b8605Smrg /* Page 679 of OpenGL 4.4 spec says: 760848b8605Smrg * "Added BlitFramebuffer to commands affected by conditional rendering in 761848b8605Smrg * section 10.10 (Bug 9562)." 762848b8605Smrg */ 763848b8605Smrg if (!_mesa_check_conditional_render(ctx)) 764848b8605Smrg return; /* Do not blit */ 765848b8605Smrg 766b8e80941Smrg if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1, 767848b8605Smrg &dstX0, &dstY0, &dstX1, &dstY1)) { 768848b8605Smrg return; 769848b8605Smrg } 770848b8605Smrg 771848b8605Smrg if (SWRAST_CONTEXT(ctx)->NewState) 772848b8605Smrg _swrast_validate_derived(ctx); 773848b8605Smrg 774848b8605Smrg /* First, try covering whatever buffers possible using the fast 1:1 copy 775848b8605Smrg * path. 776848b8605Smrg */ 777848b8605Smrg if (srcX1 - srcX0 == dstX1 - dstX0 && 778848b8605Smrg srcY1 - srcY0 == dstY1 - dstY0 && 779848b8605Smrg srcX0 < srcX1 && 780848b8605Smrg srcY0 < srcY1 && 781848b8605Smrg dstX0 < dstX1 && 782848b8605Smrg dstY0 < dstY1) { 783848b8605Smrg for (i = 0; i < 3; i++) { 784848b8605Smrg if (mask & buffers[i]) { 785b8e80941Smrg if (swrast_fast_copy_pixels(ctx, 786b8e80941Smrg readFb, drawFb, 787b8e80941Smrg srcX0, srcY0, 788b8e80941Smrg srcX1 - srcX0, srcY1 - srcY0, 789b8e80941Smrg dstX0, dstY0, 790b8e80941Smrg buffer_enums[i])) { 791b8e80941Smrg mask &= ~buffers[i]; 792b8e80941Smrg } 793b8e80941Smrg } 794848b8605Smrg } 795848b8605Smrg 796848b8605Smrg if (!mask) 797b8e80941Smrg return; 798848b8605Smrg } 799848b8605Smrg 800848b8605Smrg if (filter == GL_NEAREST) { 801848b8605Smrg for (i = 0; i < 3; i++) { 802b8e80941Smrg if (mask & buffers[i]) { 803b8e80941Smrg blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 804b8e80941Smrg dstX0, dstY0, dstX1, dstY1, buffers[i]); 805b8e80941Smrg } 806848b8605Smrg } 807848b8605Smrg } 808848b8605Smrg else { 809b8e80941Smrg assert(filter == GL_LINEAR); 810848b8605Smrg if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */ 811b8e80941Smrg blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, 812b8e80941Smrg dstX0, dstY0, dstX1, dstY1); 813848b8605Smrg } 814848b8605Smrg } 815848b8605Smrg 816848b8605Smrg} 817