1 /* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 1999-2013 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 /* 27 * glBlitFramebuffer functions. 28 */ 29 30 #include <stdbool.h> 31 #include <stdio.h> 32 33 #include "context.h" 34 #include "enums.h" 35 #include "blit.h" 36 #include "fbobject.h" 37 #include "framebuffer.h" 38 #include "glformats.h" 39 #include "mtypes.h" 40 #include "macros.h" 41 #include "state.h" 42 43 44 /** Set this to 1 to debug/log glBlitFramebuffer() calls */ 45 #define DEBUG_BLIT 0 46 47 48 49 static const struct gl_renderbuffer_attachment * 50 find_attachment(const struct gl_framebuffer *fb, 51 const struct gl_renderbuffer *rb) 52 { 53 GLuint i; 54 for (i = 0; i < ARRAY_SIZE(fb->Attachment); i++) { 55 if (fb->Attachment[i].Renderbuffer == rb) 56 return &fb->Attachment[i]; 57 } 58 return NULL; 59 } 60 61 62 /** 63 * \return true if two regions overlap, false otherwise 64 */ 65 bool 66 _mesa_regions_overlap(int srcX0, int srcY0, 67 int srcX1, int srcY1, 68 int dstX0, int dstY0, 69 int dstX1, int dstY1) 70 { 71 if (MAX2(srcX0, srcX1) <= MIN2(dstX0, dstX1)) 72 return false; /* dst completely right of src */ 73 74 if (MAX2(dstX0, dstX1) <= MIN2(srcX0, srcX1)) 75 return false; /* dst completely left of src */ 76 77 if (MAX2(srcY0, srcY1) <= MIN2(dstY0, dstY1)) 78 return false; /* dst completely above src */ 79 80 if (MAX2(dstY0, dstY1) <= MIN2(srcY0, srcY1)) 81 return false; /* dst completely below src */ 82 83 return true; /* some overlap */ 84 } 85 86 87 /** 88 * Helper function for checking if the datatypes of color buffers are 89 * compatible for glBlitFramebuffer. From the 3.1 spec, page 198: 90 * 91 * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT 92 * and any of the following conditions hold: 93 * - The read buffer contains fixed-point or floating-point values and any 94 * draw buffer contains neither fixed-point nor floating-point values. 95 * - The read buffer contains unsigned integer values and any draw buffer 96 * does not contain unsigned integer values. 97 * - The read buffer contains signed integer values and any draw buffer 98 * does not contain signed integer values." 99 */ 100 static GLboolean 101 compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat) 102 { 103 GLenum srcType = _mesa_get_format_datatype(srcFormat); 104 GLenum dstType = _mesa_get_format_datatype(dstFormat); 105 106 if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) { 107 assert(srcType == GL_UNSIGNED_NORMALIZED || 108 srcType == GL_SIGNED_NORMALIZED || 109 srcType == GL_FLOAT); 110 /* Boil any of those types down to GL_FLOAT */ 111 srcType = GL_FLOAT; 112 } 113 114 if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) { 115 assert(dstType == GL_UNSIGNED_NORMALIZED || 116 dstType == GL_SIGNED_NORMALIZED || 117 dstType == GL_FLOAT); 118 /* Boil any of those types down to GL_FLOAT */ 119 dstType = GL_FLOAT; 120 } 121 122 return srcType == dstType; 123 } 124 125 126 static GLboolean 127 compatible_resolve_formats(const struct gl_renderbuffer *readRb, 128 const struct gl_renderbuffer *drawRb) 129 { 130 GLenum readFormat, drawFormat; 131 132 /* This checks whether the internal formats are compatible rather than the 133 * Mesa format for two reasons: 134 * 135 * Under some circumstances, the user may request e.g. two GL_RGBA8 136 * textures and get two entirely different Mesa formats like RGBA8888 and 137 * ARGB8888. Drivers behaving like that should be able to cope with 138 * non-matching formats by themselves, because it's not the user's fault. 139 * 140 * Picking two different internal formats can end up with the same Mesa 141 * format. For example the driver might be simulating GL_RGB textures 142 * with GL_RGBA internally and in that case both internal formats would 143 * end up with RGBA8888. 144 * 145 * This function is used to generate a GL error according to the spec so in 146 * both cases we want to be looking at the application-level format, which 147 * is InternalFormat. 148 * 149 * Blits between linear and sRGB formats are also allowed. 150 */ 151 readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat); 152 drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat); 153 readFormat = _mesa_get_linear_internalformat(readFormat); 154 drawFormat = _mesa_get_linear_internalformat(drawFormat); 155 156 if (readFormat == drawFormat) { 157 return GL_TRUE; 158 } 159 160 return GL_FALSE; 161 } 162 163 164 static GLboolean 165 is_valid_blit_filter(const struct gl_context *ctx, GLenum filter) 166 { 167 switch (filter) { 168 case GL_NEAREST: 169 case GL_LINEAR: 170 return true; 171 case GL_SCALED_RESOLVE_FASTEST_EXT: 172 case GL_SCALED_RESOLVE_NICEST_EXT: 173 return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled; 174 default: 175 return false; 176 } 177 } 178 179 180 void 181 _mesa_blit_framebuffer(struct gl_context *ctx, 182 struct gl_framebuffer *readFb, 183 struct gl_framebuffer *drawFb, 184 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 185 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 186 GLbitfield mask, GLenum filter, const char *func) 187 { 188 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | 189 GL_DEPTH_BUFFER_BIT | 190 GL_STENCIL_BUFFER_BIT); 191 192 FLUSH_VERTICES(ctx, 0); 193 194 /* Update completeness status of readFb and drawFb. */ 195 _mesa_update_framebuffer(ctx, readFb, drawFb); 196 197 /* Make sure drawFb has an initialized bounding box. */ 198 _mesa_update_draw_buffer_bounds(ctx, drawFb); 199 200 if (!readFb || !drawFb) { 201 /* This will normally never happen but someday we may want to 202 * support MakeCurrent() with no drawables. 203 */ 204 return; 205 } 206 207 /* check for complete framebuffers */ 208 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || 209 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { 210 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, 211 "%s(incomplete draw/read buffers)", func); 212 return; 213 } 214 215 if (!is_valid_blit_filter(ctx, filter)) { 216 _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func, 217 _mesa_enum_to_string(filter)); 218 return; 219 } 220 221 if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT || 222 filter == GL_SCALED_RESOLVE_NICEST_EXT) && 223 (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) { 224 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func, 225 _mesa_enum_to_string(filter)); 226 return; 227 } 228 229 if (mask & ~legalMaskBits) { 230 _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func); 231 return; 232 } 233 234 /* depth/stencil must be blitted with nearest filtering */ 235 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) 236 && filter != GL_NEAREST) { 237 _mesa_error(ctx, GL_INVALID_OPERATION, 238 "%s(depth/stencil requires GL_NEAREST filter)", func); 239 return; 240 } 241 242 /* get color read/draw renderbuffers */ 243 if (mask & GL_COLOR_BUFFER_BIT) { 244 const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers; 245 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; 246 const struct gl_renderbuffer *colorDrawRb = NULL; 247 GLuint i; 248 249 /* From the EXT_framebuffer_object spec: 250 * 251 * "If a buffer is specified in <mask> and does not exist in both 252 * the read and draw framebuffers, the corresponding bit is silently 253 * ignored." 254 */ 255 if (!colorReadRb || numColorDrawBuffers == 0) { 256 mask &= ~GL_COLOR_BUFFER_BIT; 257 } 258 else { 259 for (i = 0; i < numColorDrawBuffers; i++) { 260 colorDrawRb = drawFb->_ColorDrawBuffers[i]; 261 if (!colorDrawRb) 262 continue; 263 264 /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL 265 * ES 3.0.1 spec says: 266 * 267 * "If the source and destination buffers are identical, an 268 * INVALID_OPERATION error is generated. Different mipmap 269 * levels of a texture, different layers of a three- 270 * dimensional texture or two-dimensional array texture, and 271 * different faces of a cube map texture do not constitute 272 * identical buffers." 273 */ 274 if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) { 275 _mesa_error(ctx, GL_INVALID_OPERATION, 276 "%s(source and destination color " 277 "buffer cannot be the same)", func); 278 return; 279 } 280 281 if (!compatible_color_datatypes(colorReadRb->Format, 282 colorDrawRb->Format)) { 283 _mesa_error(ctx, GL_INVALID_OPERATION, 284 "%s(color buffer datatypes mismatch)", func); 285 return; 286 } 287 /* extra checks for multisample copies... */ 288 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) { 289 /* color formats must match on GLES. This isn't checked on 290 * desktop GL because the GL 4.4 spec was changed to allow it. 291 * In the section entitled Changes in the released 292 * Specification of July 22, 2013 it says: 293 * 294 * Relax BlitFramebuffer in section 18.3.1 so that format 295 * conversion can take place during multisample blits, since 296 * drivers already allow this and some apps depend on it. 297 */ 298 if (_mesa_is_gles(ctx) && 299 !compatible_resolve_formats(colorReadRb, colorDrawRb)) { 300 _mesa_error(ctx, GL_INVALID_OPERATION, 301 "%s(bad src/dst multisample pixel formats)", func); 302 return; 303 } 304 } 305 } 306 if (filter != GL_NEAREST) { 307 /* From EXT_framebuffer_multisample_blit_scaled specification: 308 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error 309 * if filter is not NEAREST and read buffer contains integer data." 310 */ 311 GLenum type = _mesa_get_format_datatype(colorReadRb->Format); 312 if (type == GL_INT || type == GL_UNSIGNED_INT) { 313 _mesa_error(ctx, GL_INVALID_OPERATION, 314 "%s(integer color type)", func); 315 return; 316 } 317 } 318 } 319 } 320 321 if (mask & GL_STENCIL_BUFFER_BIT) { 322 struct gl_renderbuffer *readRb = 323 readFb->Attachment[BUFFER_STENCIL].Renderbuffer; 324 struct gl_renderbuffer *drawRb = 325 drawFb->Attachment[BUFFER_STENCIL].Renderbuffer; 326 327 /* From the EXT_framebuffer_object spec: 328 * 329 * "If a buffer is specified in <mask> and does not exist in both 330 * the read and draw framebuffers, the corresponding bit is silently 331 * ignored." 332 */ 333 if ((readRb == NULL) || (drawRb == NULL)) { 334 mask &= ~GL_STENCIL_BUFFER_BIT; 335 } 336 else { 337 int read_z_bits, draw_z_bits; 338 339 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { 340 _mesa_error(ctx, GL_INVALID_OPERATION, 341 "%s(source and destination stencil " 342 "buffer cannot be the same)", func); 343 return; 344 } 345 346 if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) != 347 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) { 348 /* There is no need to check the stencil datatype here, because 349 * there is only one: GL_UNSIGNED_INT. 350 */ 351 _mesa_error(ctx, GL_INVALID_OPERATION, 352 "%s(stencil attachment format mismatch)", func); 353 return; 354 } 355 356 read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS); 357 draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS); 358 359 /* If both buffers also have depth data, the depth formats must match 360 * as well. If one doesn't have depth, it's not blitted, so we should 361 * ignore the depth format check. 362 */ 363 if (read_z_bits > 0 && draw_z_bits > 0 && 364 (read_z_bits != draw_z_bits || 365 _mesa_get_format_datatype(readRb->Format) != 366 _mesa_get_format_datatype(drawRb->Format))) { 367 368 _mesa_error(ctx, GL_INVALID_OPERATION, 369 "%s(stencil attachment depth format mismatch)", func); 370 return; 371 } 372 } 373 } 374 375 if (mask & GL_DEPTH_BUFFER_BIT) { 376 struct gl_renderbuffer *readRb = 377 readFb->Attachment[BUFFER_DEPTH].Renderbuffer; 378 struct gl_renderbuffer *drawRb = 379 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer; 380 381 /* From the EXT_framebuffer_object spec: 382 * 383 * "If a buffer is specified in <mask> and does not exist in both 384 * the read and draw framebuffers, the corresponding bit is silently 385 * ignored." 386 */ 387 if ((readRb == NULL) || (drawRb == NULL)) { 388 mask &= ~GL_DEPTH_BUFFER_BIT; 389 } 390 else { 391 int read_s_bit, draw_s_bit; 392 393 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { 394 _mesa_error(ctx, GL_INVALID_OPERATION, 395 "%s(source and destination depth " 396 "buffer cannot be the same)", func); 397 return; 398 } 399 400 if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) != 401 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) || 402 (_mesa_get_format_datatype(readRb->Format) != 403 _mesa_get_format_datatype(drawRb->Format))) { 404 _mesa_error(ctx, GL_INVALID_OPERATION, 405 "%s(depth attachment format mismatch)", func); 406 return; 407 } 408 409 read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS); 410 draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS); 411 412 /* If both buffers also have stencil data, the stencil formats must 413 * match as well. If one doesn't have stencil, it's not blitted, so 414 * we should ignore the stencil format check. 415 */ 416 if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) { 417 _mesa_error(ctx, GL_INVALID_OPERATION, 418 "%s(depth attachment stencil bits mismatch)", func); 419 return; 420 } 421 } 422 } 423 424 425 if (_mesa_is_gles3(ctx)) { 426 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES 427 * 3.0.1 spec says: 428 * 429 * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero, 430 * an INVALID_OPERATION error is generated." 431 */ 432 if (drawFb->Visual.samples > 0) { 433 _mesa_error(ctx, GL_INVALID_OPERATION, 434 "%s(destination samples must be 0)", func); 435 return; 436 } 437 438 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES 439 * 3.0.1 spec says: 440 * 441 * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero, 442 * no copy is performed and an INVALID_OPERATION error is generated 443 * if the formats of the read and draw framebuffers are not 444 * identical or if the source and destination rectangles are not 445 * defined with the same (X0, Y0) and (X1, Y1) bounds." 446 * 447 * The format check was made above because desktop OpenGL has the same 448 * requirement. 449 */ 450 if (readFb->Visual.samples > 0 451 && (srcX0 != dstX0 || srcY0 != dstY0 452 || srcX1 != dstX1 || srcY1 != dstY1)) { 453 _mesa_error(ctx, GL_INVALID_OPERATION, 454 "%s(bad src/dst multisample region)", func); 455 return; 456 } 457 } else { 458 if (readFb->Visual.samples > 0 && 459 drawFb->Visual.samples > 0 && 460 readFb->Visual.samples != drawFb->Visual.samples) { 461 _mesa_error(ctx, GL_INVALID_OPERATION, 462 "%s(mismatched samples)", func); 463 return; 464 } 465 466 /* extra checks for multisample copies... */ 467 if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) && 468 (filter == GL_NEAREST || filter == GL_LINEAR)) { 469 /* src and dest region sizes must be the same */ 470 if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || 471 abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { 472 _mesa_error(ctx, GL_INVALID_OPERATION, 473 "%s(bad src/dst multisample region sizes)", func); 474 return; 475 } 476 } 477 } 478 479 /* Debug code */ 480 if (DEBUG_BLIT) { 481 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; 482 const struct gl_renderbuffer *colorDrawRb = NULL; 483 GLuint i = 0; 484 485 printf("%s(%d, %d, %d, %d, %d, %d, %d, %d," 486 " 0x%x, 0x%x)\n", func, 487 srcX0, srcY0, srcX1, srcY1, 488 dstX0, dstY0, dstX1, dstY1, 489 mask, filter); 490 491 if (colorReadRb) { 492 const struct gl_renderbuffer_attachment *att; 493 494 att = find_attachment(readFb, colorReadRb); 495 printf(" Src FBO %u RB %u (%dx%d) ", 496 readFb->Name, colorReadRb->Name, 497 colorReadRb->Width, colorReadRb->Height); 498 if (att && att->Texture) { 499 printf("Tex %u tgt 0x%x level %u face %u", 500 att->Texture->Name, 501 att->Texture->Target, 502 att->TextureLevel, 503 att->CubeMapFace); 504 } 505 printf("\n"); 506 507 /* Print all active color render buffers */ 508 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { 509 colorDrawRb = drawFb->_ColorDrawBuffers[i]; 510 if (!colorDrawRb) 511 continue; 512 513 att = find_attachment(drawFb, colorDrawRb); 514 printf(" Dst FBO %u RB %u (%dx%d) ", 515 drawFb->Name, colorDrawRb->Name, 516 colorDrawRb->Width, colorDrawRb->Height); 517 if (att && att->Texture) { 518 printf("Tex %u tgt 0x%x level %u face %u", 519 att->Texture->Name, 520 att->Texture->Target, 521 att->TextureLevel, 522 att->CubeMapFace); 523 } 524 printf("\n"); 525 } 526 } 527 } 528 529 if (!mask || 530 (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 || 531 (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) { 532 return; 533 } 534 535 assert(ctx->Driver.BlitFramebuffer); 536 ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb, 537 srcX0, srcY0, srcX1, srcY1, 538 dstX0, dstY0, dstX1, dstY1, 539 mask, filter); 540 } 541 542 543 /** 544 * Blit rectangular region, optionally from one framebuffer to another. 545 * 546 * Note, if the src buffer is multisampled and the dest is not, this is 547 * when the samples must be resolved to a single color. 548 */ 549 void GLAPIENTRY 550 _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 551 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 552 GLbitfield mask, GLenum filter) 553 { 554 GET_CURRENT_CONTEXT(ctx); 555 556 if (MESA_VERBOSE & VERBOSE_API) 557 _mesa_debug(ctx, 558 "glBlitFramebuffer(%d, %d, %d, %d, " 559 " %d, %d, %d, %d, 0x%x, %s)\n", 560 srcX0, srcY0, srcX1, srcY1, 561 dstX0, dstY0, dstX1, dstY1, 562 mask, _mesa_enum_to_string(filter)); 563 564 _mesa_blit_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, 565 srcX0, srcY0, srcX1, srcY1, 566 dstX0, dstY0, dstX1, dstY1, 567 mask, filter, "glBlitFramebuffer"); 568 } 569 570 571 void GLAPIENTRY 572 _mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, 573 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 574 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 575 GLbitfield mask, GLenum filter) 576 { 577 GET_CURRENT_CONTEXT(ctx); 578 struct gl_framebuffer *readFb, *drawFb; 579 580 if (MESA_VERBOSE & VERBOSE_API) 581 _mesa_debug(ctx, 582 "glBlitNamedFramebuffer(%u %u %d, %d, %d, %d, " 583 " %d, %d, %d, %d, 0x%x, %s)\n", 584 readFramebuffer, drawFramebuffer, 585 srcX0, srcY0, srcX1, srcY1, 586 dstX0, dstY0, dstX1, dstY1, 587 mask, _mesa_enum_to_string(filter)); 588 589 /* 590 * According to PDF page 533 of the OpenGL 4.5 core spec (30.10.2014, 591 * Section 18.3 Copying Pixels): 592 * "... if readFramebuffer or drawFramebuffer is zero (for 593 * BlitNamedFramebuffer), then the default read or draw framebuffer is 594 * used as the corresponding source or destination framebuffer, 595 * respectively." 596 */ 597 if (readFramebuffer) { 598 readFb = _mesa_lookup_framebuffer_err(ctx, readFramebuffer, 599 "glBlitNamedFramebuffer"); 600 if (!readFb) 601 return; 602 } 603 else 604 readFb = ctx->WinSysReadBuffer; 605 606 if (drawFramebuffer) { 607 drawFb = _mesa_lookup_framebuffer_err(ctx, drawFramebuffer, 608 "glBlitNamedFramebuffer"); 609 if (!drawFb) 610 return; 611 } 612 else 613 drawFb = ctx->WinSysDrawBuffer; 614 615 _mesa_blit_framebuffer(ctx, readFb, drawFb, 616 srcX0, srcY0, srcX1, srcY1, 617 dstX0, dstY0, dstX1, dstY1, 618 mask, filter, "glBlitNamedFramebuffer"); 619 } 620