4765198d63a724baae435d1099ea3b251222d878
[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 /* The simple case where we know the backing Mesa formats are the same.
133 */
134 if (_mesa_get_srgb_format_linear(readRb->Format) ==
135 _mesa_get_srgb_format_linear(drawRb->Format)) {
136 return GL_TRUE;
137 }
138
139 /* The Mesa formats are different, so we must check whether the internal
140 * formats are compatible.
141 *
142 * Under some circumstances, the user may request e.g. two GL_RGBA8
143 * textures and get two entirely different Mesa formats like RGBA8888 and
144 * ARGB8888. Drivers behaving like that should be able to cope with
145 * non-matching formats by themselves, because it's not the user's fault.
146 *
147 * Blits between linear and sRGB formats are also allowed.
148 */
149 readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
150 drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
151 readFormat = _mesa_get_linear_internalformat(readFormat);
152 drawFormat = _mesa_get_linear_internalformat(drawFormat);
153
154 if (readFormat == drawFormat) {
155 return GL_TRUE;
156 }
157
158 return GL_FALSE;
159 }
160
161
162 static GLboolean
163 is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
164 {
165 switch (filter) {
166 case GL_NEAREST:
167 case GL_LINEAR:
168 return true;
169 case GL_SCALED_RESOLVE_FASTEST_EXT:
170 case GL_SCALED_RESOLVE_NICEST_EXT:
171 return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
172 default:
173 return false;
174 }
175 }
176
177
178 void
179 _mesa_blit_framebuffer(struct gl_context *ctx,
180 struct gl_framebuffer *readFb,
181 struct gl_framebuffer *drawFb,
182 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
183 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
184 GLbitfield mask, GLenum filter, const char *func)
185 {
186 const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
187 GL_DEPTH_BUFFER_BIT |
188 GL_STENCIL_BUFFER_BIT);
189
190 FLUSH_VERTICES(ctx, 0);
191
192 /* Update completeness status of readFb and drawFb. */
193 _mesa_update_framebuffer(ctx, readFb, drawFb);
194
195 /* Make sure drawFb has an initialized bounding box. */
196 _mesa_update_draw_buffer_bounds(ctx, drawFb);
197
198 if (!readFb || !drawFb) {
199 /* This will normally never happen but someday we may want to
200 * support MakeCurrent() with no drawables.
201 */
202 return;
203 }
204
205 /* check for complete framebuffers */
206 if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
207 readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
208 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
209 "%s(incomplete draw/read buffers)", func);
210 return;
211 }
212
213 if (!is_valid_blit_filter(ctx, filter)) {
214 _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func,
215 _mesa_lookup_enum_by_nr(filter));
216 return;
217 }
218
219 if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
220 filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
221 (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
222 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func,
223 _mesa_lookup_enum_by_nr(filter));
224 return;
225 }
226
227 if (mask & ~legalMaskBits) {
228 _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func);
229 return;
230 }
231
232 /* depth/stencil must be blitted with nearest filtering */
233 if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
234 && filter != GL_NEAREST) {
235 _mesa_error(ctx, GL_INVALID_OPERATION,
236 "%s(depth/stencil requires GL_NEAREST filter)", func);
237 return;
238 }
239
240 /* get color read/draw renderbuffers */
241 if (mask & GL_COLOR_BUFFER_BIT) {
242 const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers;
243 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
244 const struct gl_renderbuffer *colorDrawRb = NULL;
245 GLuint i;
246
247 /* From the EXT_framebuffer_object spec:
248 *
249 * "If a buffer is specified in <mask> and does not exist in both
250 * the read and draw framebuffers, the corresponding bit is silently
251 * ignored."
252 */
253 if (!colorReadRb || numColorDrawBuffers == 0) {
254 mask &= ~GL_COLOR_BUFFER_BIT;
255 }
256 else {
257 for (i = 0; i < numColorDrawBuffers; i++) {
258 colorDrawRb = drawFb->_ColorDrawBuffers[i];
259 if (!colorDrawRb)
260 continue;
261
262 /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
263 * ES 3.0.1 spec says:
264 *
265 * "If the source and destination buffers are identical, an
266 * INVALID_OPERATION error is generated. Different mipmap
267 * levels of a texture, different layers of a three-
268 * dimensional texture or two-dimensional array texture, and
269 * different faces of a cube map texture do not constitute
270 * identical buffers."
271 */
272 if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
273 _mesa_error(ctx, GL_INVALID_OPERATION,
274 "%s(source and destination color "
275 "buffer cannot be the same)", func);
276 return;
277 }
278
279 if (!compatible_color_datatypes(colorReadRb->Format,
280 colorDrawRb->Format)) {
281 _mesa_error(ctx, GL_INVALID_OPERATION,
282 "%s(color buffer datatypes mismatch)", func);
283 return;
284 }
285 /* extra checks for multisample copies... */
286 if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
287 /* color formats must match */
288 if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
289 _mesa_error(ctx, GL_INVALID_OPERATION,
290 "%s(bad src/dst multisample pixel formats)", func);
291 return;
292 }
293 }
294 }
295 if (filter != GL_NEAREST) {
296 /* From EXT_framebuffer_multisample_blit_scaled specification:
297 * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
298 * if filter is not NEAREST and read buffer contains integer data."
299 */
300 GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
301 if (type == GL_INT || type == GL_UNSIGNED_INT) {
302 _mesa_error(ctx, GL_INVALID_OPERATION,
303 "%s(integer color type)", func);
304 return;
305 }
306 }
307 }
308 }
309
310 if (mask & GL_STENCIL_BUFFER_BIT) {
311 struct gl_renderbuffer *readRb =
312 readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
313 struct gl_renderbuffer *drawRb =
314 drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
315
316 /* From the EXT_framebuffer_object spec:
317 *
318 * "If a buffer is specified in <mask> and does not exist in both
319 * the read and draw framebuffers, the corresponding bit is silently
320 * ignored."
321 */
322 if ((readRb == NULL) || (drawRb == NULL)) {
323 mask &= ~GL_STENCIL_BUFFER_BIT;
324 }
325 else {
326 int read_z_bits, draw_z_bits;
327
328 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
329 _mesa_error(ctx, GL_INVALID_OPERATION,
330 "%s(source and destination stencil "
331 "buffer cannot be the same)", func);
332 return;
333 }
334
335 if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
336 _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
337 /* There is no need to check the stencil datatype here, because
338 * there is only one: GL_UNSIGNED_INT.
339 */
340 _mesa_error(ctx, GL_INVALID_OPERATION,
341 "%s(stencil attachment format mismatch)", func);
342 return;
343 }
344
345 read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
346 draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
347
348 /* If both buffers also have depth data, the depth formats must match
349 * as well. If one doesn't have depth, it's not blitted, so we should
350 * ignore the depth format check.
351 */
352 if (read_z_bits > 0 && draw_z_bits > 0 &&
353 (read_z_bits != draw_z_bits ||
354 _mesa_get_format_datatype(readRb->Format) !=
355 _mesa_get_format_datatype(drawRb->Format))) {
356
357 _mesa_error(ctx, GL_INVALID_OPERATION,
358 "%s(stencil attachment depth format mismatch)", func);
359 return;
360 }
361 }
362 }
363
364 if (mask & GL_DEPTH_BUFFER_BIT) {
365 struct gl_renderbuffer *readRb =
366 readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
367 struct gl_renderbuffer *drawRb =
368 drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
369
370 /* From the EXT_framebuffer_object spec:
371 *
372 * "If a buffer is specified in <mask> and does not exist in both
373 * the read and draw framebuffers, the corresponding bit is silently
374 * ignored."
375 */
376 if ((readRb == NULL) || (drawRb == NULL)) {
377 mask &= ~GL_DEPTH_BUFFER_BIT;
378 }
379 else {
380 int read_s_bit, draw_s_bit;
381
382 if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
383 _mesa_error(ctx, GL_INVALID_OPERATION,
384 "%s(source and destination depth "
385 "buffer cannot be the same)", func);
386 return;
387 }
388
389 if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
390 _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
391 (_mesa_get_format_datatype(readRb->Format) !=
392 _mesa_get_format_datatype(drawRb->Format))) {
393 _mesa_error(ctx, GL_INVALID_OPERATION,
394 "%s(depth attachment format mismatch)", func);
395 return;
396 }
397
398 read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
399 draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
400
401 /* If both buffers also have stencil data, the stencil formats must
402 * match as well. If one doesn't have stencil, it's not blitted, so
403 * we should ignore the stencil format check.
404 */
405 if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
406 _mesa_error(ctx, GL_INVALID_OPERATION,
407 "%s(depth attachment stencil bits mismatch)", func);
408 return;
409 }
410 }
411 }
412
413
414 if (_mesa_is_gles3(ctx)) {
415 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
416 * 3.0.1 spec says:
417 *
418 * "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
419 * an INVALID_OPERATION error is generated."
420 */
421 if (drawFb->Visual.samples > 0) {
422 _mesa_error(ctx, GL_INVALID_OPERATION,
423 "%s(destination samples must be 0)", func);
424 return;
425 }
426
427 /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
428 * 3.0.1 spec says:
429 *
430 * "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
431 * no copy is performed and an INVALID_OPERATION error is generated
432 * if the formats of the read and draw framebuffers are not
433 * identical or if the source and destination rectangles are not
434 * defined with the same (X0, Y0) and (X1, Y1) bounds."
435 *
436 * The format check was made above because desktop OpenGL has the same
437 * requirement.
438 */
439 if (readFb->Visual.samples > 0
440 && (srcX0 != dstX0 || srcY0 != dstY0
441 || srcX1 != dstX1 || srcY1 != dstY1)) {
442 _mesa_error(ctx, GL_INVALID_OPERATION,
443 "%s(bad src/dst multisample region)", func);
444 return;
445 }
446 } else {
447 if (readFb->Visual.samples > 0 &&
448 drawFb->Visual.samples > 0 &&
449 readFb->Visual.samples != drawFb->Visual.samples) {
450 _mesa_error(ctx, GL_INVALID_OPERATION,
451 "%s(mismatched samples)", func);
452 return;
453 }
454
455 /* extra checks for multisample copies... */
456 if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
457 (filter == GL_NEAREST || filter == GL_LINEAR)) {
458 /* src and dest region sizes must be the same */
459 if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
460 abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
461 _mesa_error(ctx, GL_INVALID_OPERATION,
462 "%s(bad src/dst multisample region sizes)", func);
463 return;
464 }
465 }
466 }
467
468 /* Debug code */
469 if (DEBUG_BLIT) {
470 const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
471 const struct gl_renderbuffer *colorDrawRb = NULL;
472 GLuint i = 0;
473
474 printf("%s(%d, %d, %d, %d, %d, %d, %d, %d,"
475 " 0x%x, 0x%x)\n", func,
476 srcX0, srcY0, srcX1, srcY1,
477 dstX0, dstY0, dstX1, dstY1,
478 mask, filter);
479
480 if (colorReadRb) {
481 const struct gl_renderbuffer_attachment *att;
482
483 att = find_attachment(readFb, colorReadRb);
484 printf(" Src FBO %u RB %u (%dx%d) ",
485 readFb->Name, colorReadRb->Name,
486 colorReadRb->Width, colorReadRb->Height);
487 if (att && att->Texture) {
488 printf("Tex %u tgt 0x%x level %u face %u",
489 att->Texture->Name,
490 att->Texture->Target,
491 att->TextureLevel,
492 att->CubeMapFace);
493 }
494 printf("\n");
495
496 /* Print all active color render buffers */
497 for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
498 colorDrawRb = drawFb->_ColorDrawBuffers[i];
499 if (!colorDrawRb)
500 continue;
501
502 att = find_attachment(drawFb, colorDrawRb);
503 printf(" Dst FBO %u RB %u (%dx%d) ",
504 drawFb->Name, colorDrawRb->Name,
505 colorDrawRb->Width, colorDrawRb->Height);
506 if (att && att->Texture) {
507 printf("Tex %u tgt 0x%x level %u face %u",
508 att->Texture->Name,
509 att->Texture->Target,
510 att->TextureLevel,
511 att->CubeMapFace);
512 }
513 printf("\n");
514 }
515 }
516 }
517
518 if (!mask ||
519 (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
520 (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
521 return;
522 }
523
524 assert(ctx->Driver.BlitFramebuffer);
525 ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb,
526 srcX0, srcY0, srcX1, srcY1,
527 dstX0, dstY0, dstX1, dstY1,
528 mask, filter);
529 }
530
531
532 /**
533 * Blit rectangular region, optionally from one framebuffer to another.
534 *
535 * Note, if the src buffer is multisampled and the dest is not, this is
536 * when the samples must be resolved to a single color.
537 */
538 void GLAPIENTRY
539 _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
540 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
541 GLbitfield mask, GLenum filter)
542 {
543 GET_CURRENT_CONTEXT(ctx);
544
545 if (MESA_VERBOSE & VERBOSE_API)
546 _mesa_debug(ctx,
547 "glBlitFramebuffer(%d, %d, %d, %d, "
548 " %d, %d, %d, %d, 0x%x, %s)\n",
549 srcX0, srcY0, srcX1, srcY1,
550 dstX0, dstY0, dstX1, dstY1,
551 mask, _mesa_lookup_enum_by_nr(filter));
552
553 _mesa_blit_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
554 srcX0, srcY0, srcX1, srcY1,
555 dstX0, dstY0, dstX1, dstY1,
556 mask, filter, "glBlitFramebuffer");
557 }
558
559
560 void GLAPIENTRY
561 _mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer,
562 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
563 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
564 GLbitfield mask, GLenum filter)
565 {
566 GET_CURRENT_CONTEXT(ctx);
567 struct gl_framebuffer *readFb, *drawFb;
568
569 if (MESA_VERBOSE & VERBOSE_API)
570 _mesa_debug(ctx,
571 "glBlitNamedFramebuffer(%u %u %d, %d, %d, %d, "
572 " %d, %d, %d, %d, 0x%x, %s)\n",
573 readFramebuffer, drawFramebuffer,
574 srcX0, srcY0, srcX1, srcY1,
575 dstX0, dstY0, dstX1, dstY1,
576 mask, _mesa_lookup_enum_by_nr(filter));
577
578 /*
579 * According to PDF page 533 of the OpenGL 4.5 core spec (30.10.2014,
580 * Section 18.3 Copying Pixels):
581 * "... if readFramebuffer or drawFramebuffer is zero (for
582 * BlitNamedFramebuffer), then the default read or draw framebuffer is
583 * used as the corresponding source or destination framebuffer,
584 * respectively."
585 */
586 if (readFramebuffer) {
587 readFb = _mesa_lookup_framebuffer_err(ctx, readFramebuffer,
588 "glBlitNamedFramebuffer");
589 if (!readFb)
590 return;
591 }
592 else
593 readFb = ctx->WinSysReadBuffer;
594
595 if (drawFramebuffer) {
596 drawFb = _mesa_lookup_framebuffer_err(ctx, drawFramebuffer,
597 "glBlitNamedFramebuffer");
598 if (!drawFb)
599 return;
600 }
601 else
602 drawFb = ctx->WinSysDrawBuffer;
603
604 _mesa_blit_framebuffer(ctx, readFb, drawFb,
605 srcX0, srcY0, srcX1, srcY1,
606 dstX0, dstY0, dstX1, dstY1,
607 mask, filter, "glBlitNamedFramebuffer");
608 }