mesa: add 'no_error' parameter to blit_framebuffer()
[mesa.git] / src / mesa / main / blit.c
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 static void
181 blit_framebuffer(struct gl_context *ctx,
182 struct gl_framebuffer *readFb, struct gl_framebuffer *drawFb,
183 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
184 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
185 GLbitfield mask, GLenum filter, bool no_error, const char *func)
186 {
187 FLUSH_VERTICES(ctx, 0);
188
189 /* Update completeness status of readFb and drawFb. */
190 _mesa_update_framebuffer(ctx, readFb, drawFb);
191
192 /* Make sure drawFb has an initialized bounding box. */
193 _mesa_update_draw_buffer_bounds(ctx, drawFb);
194
195 if (!readFb || !drawFb) {
196 /* This will normally never happen but someday we may want to
197 * support MakeCurrent() with no drawables.
198 */
199 return;
200 }
201
202 if (!no_error) {
203 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
204 GL_DEPTH_BUFFER_BIT |
205 GL_STENCIL_BUFFER_BIT);
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 if (_mesa_is_gles3(ctx)) {
243 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
244 * 3.0.1 spec says:
245 *
246 * "If SAMPLE_BUFFERS for the draw framebuffer is greater than
247 * zero, an INVALID_OPERATION error is generated."
248 */
249 if (drawFb->Visual.samples > 0) {
250 _mesa_error(ctx, GL_INVALID_OPERATION,
251 "%s(destination samples must be 0)", func);
252 return;
253 }
254
255 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
256 * 3.0.1 spec says:
257 *
258 * "If SAMPLE_BUFFERS for the read framebuffer is greater than
259 * zero, no copy is performed and an INVALID_OPERATION error is
260 * generated if the formats of the read and draw framebuffers are
261 * not identical or if the source and destination rectangles are
262 * not defined with the same (X0, Y0) and (X1, Y1) bounds."
263 *
264 * The format check was made above because desktop OpenGL has the same
265 * requirement.
266 */
267 if (readFb->Visual.samples > 0
268 && (srcX0 != dstX0 || srcY0 != dstY0
269 || srcX1 != dstX1 || srcY1 != dstY1)) {
270 _mesa_error(ctx, GL_INVALID_OPERATION,
271 "%s(bad src/dst multisample region)", func);
272 return;
273 }
274 } else {
275 if (readFb->Visual.samples > 0 &&
276 drawFb->Visual.samples > 0 &&
277 readFb->Visual.samples != drawFb->Visual.samples) {
278 _mesa_error(ctx, GL_INVALID_OPERATION,
279 "%s(mismatched samples)", func);
280 return;
281 }
282
283 /* extra checks for multisample copies... */
284 if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
285 (filter == GL_NEAREST || filter == GL_LINEAR)) {
286 /* src and dest region sizes must be the same */
287 if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
288 abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
289 _mesa_error(ctx, GL_INVALID_OPERATION,
290 "%s(bad src/dst multisample region sizes)", func);
291 return;
292 }
293 }
294 }
295 }
296
297 /* get color read/draw renderbuffers */
298 if (mask & GL_COLOR_BUFFER_BIT) {
299 const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers;
300 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
301 const struct gl_renderbuffer *colorDrawRb = NULL;
302 GLuint i;
303
304 /* From the EXT_framebuffer_object spec:
305 *
306 * "If a buffer is specified in <mask> and does not exist in both
307 * the read and draw framebuffers, the corresponding bit is silently
308 * ignored."
309 */
310 if (!colorReadRb || numColorDrawBuffers == 0) {
311 mask &= ~GL_COLOR_BUFFER_BIT;
312 } else if (!no_error) {
313 for (i = 0; i < numColorDrawBuffers; i++) {
314 colorDrawRb = drawFb->_ColorDrawBuffers[i];
315 if (!colorDrawRb)
316 continue;
317
318 /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
319 * ES 3.0.1 spec says:
320 *
321 * "If the source and destination buffers are identical, an
322 * INVALID_OPERATION error is generated. Different mipmap
323 * levels of a texture, different layers of a three-
324 * dimensional texture or two-dimensional array texture, and
325 * different faces of a cube map texture do not constitute
326 * identical buffers."
327 */
328 if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
329 _mesa_error(ctx, GL_INVALID_OPERATION,
330 "%s(source and destination color "
331 "buffer cannot be the same)", func);
332 return;
333 }
334
335 if (!compatible_color_datatypes(colorReadRb->Format,
336 colorDrawRb->Format)) {
337 _mesa_error(ctx, GL_INVALID_OPERATION,
338 "%s(color buffer datatypes mismatch)", func);
339 return;
340 }
341 /* extra checks for multisample copies... */
342 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
343 /* color formats must match on GLES. This isn't checked on
344 * desktop GL because the GL 4.4 spec was changed to allow it.
345 * In the section entitled “Changes in the released
346 * Specification of July 22, 2013” it says:
347 *
348 * “Relax BlitFramebuffer in section 18.3.1 so that format
349 * conversion can take place during multisample blits, since
350 * drivers already allow this and some apps depend on it.”
351 */
352 if (_mesa_is_gles(ctx) &&
353 !compatible_resolve_formats(colorReadRb, colorDrawRb)) {
354 _mesa_error(ctx, GL_INVALID_OPERATION,
355 "%s(bad src/dst multisample pixel formats)", func);
356 return;
357 }
358 }
359 }
360 if (filter != GL_NEAREST) {
361 /* From EXT_framebuffer_multisample_blit_scaled specification:
362 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
363 * if filter is not NEAREST and read buffer contains integer data."
364 */
365 GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
366 if (type == GL_INT || type == GL_UNSIGNED_INT) {
367 _mesa_error(ctx, GL_INVALID_OPERATION,
368 "%s(integer color type)", func);
369 return;
370 }
371 }
372 }
373 }
374
375 if (mask & GL_STENCIL_BUFFER_BIT) {
376 struct gl_renderbuffer *readRb =
377 readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
378 struct gl_renderbuffer *drawRb =
379 drawFb->Attachment[BUFFER_STENCIL].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_STENCIL_BUFFER_BIT;
389 } else if (!no_error) {
390 int read_z_bits, draw_z_bits;
391
392 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
393 _mesa_error(ctx, GL_INVALID_OPERATION,
394 "%s(source and destination stencil "
395 "buffer cannot be the same)", func);
396 return;
397 }
398
399 if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
400 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
401 /* There is no need to check the stencil datatype here, because
402 * there is only one: GL_UNSIGNED_INT.
403 */
404 _mesa_error(ctx, GL_INVALID_OPERATION,
405 "%s(stencil attachment format mismatch)", func);
406 return;
407 }
408
409 read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
410 draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
411
412 /* If both buffers also have depth data, the depth formats must match
413 * as well. If one doesn't have depth, it's not blitted, so we should
414 * ignore the depth format check.
415 */
416 if (read_z_bits > 0 && draw_z_bits > 0 &&
417 (read_z_bits != draw_z_bits ||
418 _mesa_get_format_datatype(readRb->Format) !=
419 _mesa_get_format_datatype(drawRb->Format))) {
420
421 _mesa_error(ctx, GL_INVALID_OPERATION,
422 "%s(stencil attachment depth format mismatch)", func);
423 return;
424 }
425 }
426 }
427
428 if (mask & GL_DEPTH_BUFFER_BIT) {
429 struct gl_renderbuffer *readRb =
430 readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
431 struct gl_renderbuffer *drawRb =
432 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
433
434 /* From the EXT_framebuffer_object spec:
435 *
436 * "If a buffer is specified in <mask> and does not exist in both
437 * the read and draw framebuffers, the corresponding bit is silently
438 * ignored."
439 */
440 if ((readRb == NULL) || (drawRb == NULL)) {
441 mask &= ~GL_DEPTH_BUFFER_BIT;
442 } else if (!no_error) {
443 int read_s_bit, draw_s_bit;
444
445 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
446 _mesa_error(ctx, GL_INVALID_OPERATION,
447 "%s(source and destination depth "
448 "buffer cannot be the same)", func);
449 return;
450 }
451
452 if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
453 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
454 (_mesa_get_format_datatype(readRb->Format) !=
455 _mesa_get_format_datatype(drawRb->Format))) {
456 _mesa_error(ctx, GL_INVALID_OPERATION,
457 "%s(depth attachment format mismatch)", func);
458 return;
459 }
460
461 read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
462 draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
463
464 /* If both buffers also have stencil data, the stencil formats must
465 * match as well. If one doesn't have stencil, it's not blitted, so
466 * we should ignore the stencil format check.
467 */
468 if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
469 _mesa_error(ctx, GL_INVALID_OPERATION,
470 "%s(depth attachment stencil bits mismatch)", func);
471 return;
472 }
473 }
474 }
475
476 /* Debug code */
477 if (DEBUG_BLIT) {
478 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
479 const struct gl_renderbuffer *colorDrawRb = NULL;
480 GLuint i = 0;
481
482 printf("%s(%d, %d, %d, %d, %d, %d, %d, %d,"
483 " 0x%x, 0x%x)\n", func,
484 srcX0, srcY0, srcX1, srcY1,
485 dstX0, dstY0, dstX1, dstY1,
486 mask, filter);
487
488 if (colorReadRb) {
489 const struct gl_renderbuffer_attachment *att;
490
491 att = find_attachment(readFb, colorReadRb);
492 printf(" Src FBO %u RB %u (%dx%d) ",
493 readFb->Name, colorReadRb->Name,
494 colorReadRb->Width, colorReadRb->Height);
495 if (att && att->Texture) {
496 printf("Tex %u tgt 0x%x level %u face %u",
497 att->Texture->Name,
498 att->Texture->Target,
499 att->TextureLevel,
500 att->CubeMapFace);
501 }
502 printf("\n");
503
504 /* Print all active color render buffers */
505 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
506 colorDrawRb = drawFb->_ColorDrawBuffers[i];
507 if (!colorDrawRb)
508 continue;
509
510 att = find_attachment(drawFb, colorDrawRb);
511 printf(" Dst FBO %u RB %u (%dx%d) ",
512 drawFb->Name, colorDrawRb->Name,
513 colorDrawRb->Width, colorDrawRb->Height);
514 if (att && att->Texture) {
515 printf("Tex %u tgt 0x%x level %u face %u",
516 att->Texture->Name,
517 att->Texture->Target,
518 att->TextureLevel,
519 att->CubeMapFace);
520 }
521 printf("\n");
522 }
523 }
524 }
525
526 if (!mask ||
527 (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
528 (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
529 return;
530 }
531
532 assert(ctx->Driver.BlitFramebuffer);
533 ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb,
534 srcX0, srcY0, srcX1, srcY1,
535 dstX0, dstY0, dstX1, dstY1,
536 mask, filter);
537 }
538
539
540 /**
541 * Blit rectangular region, optionally from one framebuffer to another.
542 *
543 * Note, if the src buffer is multisampled and the dest is not, this is
544 * when the samples must be resolved to a single color.
545 */
546 void GLAPIENTRY
547 _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
548 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
549 GLbitfield mask, GLenum filter)
550 {
551 GET_CURRENT_CONTEXT(ctx);
552
553 if (MESA_VERBOSE & VERBOSE_API)
554 _mesa_debug(ctx,
555 "glBlitFramebuffer(%d, %d, %d, %d, "
556 " %d, %d, %d, %d, 0x%x, %s)\n",
557 srcX0, srcY0, srcX1, srcY1,
558 dstX0, dstY0, dstX1, dstY1,
559 mask, _mesa_enum_to_string(filter));
560
561 blit_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
562 srcX0, srcY0, srcX1, srcY1,
563 dstX0, dstY0, dstX1, dstY1,
564 mask, filter, false, "glBlitFramebuffer");
565 }
566
567
568 void GLAPIENTRY
569 _mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer,
570 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
571 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
572 GLbitfield mask, GLenum filter)
573 {
574 GET_CURRENT_CONTEXT(ctx);
575 struct gl_framebuffer *readFb, *drawFb;
576
577 if (MESA_VERBOSE & VERBOSE_API)
578 _mesa_debug(ctx,
579 "glBlitNamedFramebuffer(%u %u %d, %d, %d, %d, "
580 " %d, %d, %d, %d, 0x%x, %s)\n",
581 readFramebuffer, drawFramebuffer,
582 srcX0, srcY0, srcX1, srcY1,
583 dstX0, dstY0, dstX1, dstY1,
584 mask, _mesa_enum_to_string(filter));
585
586 /*
587 * According to PDF page 533 of the OpenGL 4.5 core spec (30.10.2014,
588 * Section 18.3 Copying Pixels):
589 * "... if readFramebuffer or drawFramebuffer is zero (for
590 * BlitNamedFramebuffer), then the default read or draw framebuffer is
591 * used as the corresponding source or destination framebuffer,
592 * respectively."
593 */
594 if (readFramebuffer) {
595 readFb = _mesa_lookup_framebuffer_err(ctx, readFramebuffer,
596 "glBlitNamedFramebuffer");
597 if (!readFb)
598 return;
599 }
600 else
601 readFb = ctx->WinSysReadBuffer;
602
603 if (drawFramebuffer) {
604 drawFb = _mesa_lookup_framebuffer_err(ctx, drawFramebuffer,
605 "glBlitNamedFramebuffer");
606 if (!drawFb)
607 return;
608 }
609 else
610 drawFb = ctx->WinSysDrawBuffer;
611
612 blit_framebuffer(ctx, readFb, drawFb,
613 srcX0, srcY0, srcX1, srcY1,
614 dstX0, dstY0, dstX1, dstY1,
615 mask, filter, false, "glBlitNamedFramebuffer");
616 }