1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "main/glheader.h"
26 #include "main/mtypes.h"
27 #include "main/arbprogram.h"
28 #include "main/arrayobj.h"
29 #include "main/blend.h"
30 #include "main/depth.h"
31 #include "main/enable.h"
32 #include "main/enums.h"
33 #include "main/fbobject.h"
34 #include "main/image.h"
35 #include "main/macros.h"
36 #include "main/matrix.h"
37 #include "main/readpix.h"
38 #include "main/scissor.h"
39 #include "main/shaderapi.h"
40 #include "main/texobj.h"
41 #include "main/texenv.h"
42 #include "main/teximage.h"
43 #include "main/texparam.h"
44 #include "main/uniforms.h"
45 #include "main/varray.h"
46 #include "main/viewport.h"
47 #include "swrast/swrast.h"
48 #include "drivers/common/meta.h"
49
50 static struct gl_texture_object *
51 texture_object_from_renderbuffer(struct gl_context *, struct gl_renderbuffer *);
52
53 static struct gl_sampler_object *
54 setup_sampler(struct gl_context *, struct gl_texture_object *, GLenum target,
55 GLenum filter, GLuint srcLevel);
56
57 /** Return offset in bytes of the field within a vertex struct */
58 #define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
59
60 static void
setup_glsl_blit_framebuffer(struct gl_context * ctx,struct blit_state * blit,const struct gl_framebuffer * drawFb,struct gl_renderbuffer * src_rb,GLenum target,bool do_depth)61 setup_glsl_blit_framebuffer(struct gl_context *ctx,
62 struct blit_state *blit,
63 const struct gl_framebuffer *drawFb,
64 struct gl_renderbuffer *src_rb,
65 GLenum target,
66 bool do_depth)
67 {
68 const unsigned texcoord_size = 2 + (src_rb->Depth > 1 ? 1 : 0);
69
70 /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */
71 assert(_mesa_is_desktop_gl(ctx) || target == GL_TEXTURE_2D);
72
73
74 _mesa_meta_setup_vertex_objects(ctx, &blit->VAO, &blit->buf_obj, true,
75 2, texcoord_size, 0);
76
77 _mesa_meta_setup_blit_shader(ctx, target, do_depth,
78 do_depth ? &blit->shaders_with_depth
79 : &blit->shaders_without_depth);
80 }
81
82 /**
83 * Try to do a color or depth glBlitFramebuffer using texturing.
84 *
85 * We can do this when the src renderbuffer is actually a texture, or when the
86 * driver exposes BindRenderbufferTexImage().
87 */
88 static bool
blitframebuffer_texture(struct gl_context * ctx,const struct gl_framebuffer * readFb,const struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLenum filter,GLint flipX,GLint flipY,GLboolean glsl_version,GLboolean do_depth)89 blitframebuffer_texture(struct gl_context *ctx,
90 const struct gl_framebuffer *readFb,
91 const struct gl_framebuffer *drawFb,
92 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
93 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
94 GLenum filter, GLint flipX, GLint flipY,
95 GLboolean glsl_version, GLboolean do_depth)
96 {
97 int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex;
98 const struct gl_renderbuffer_attachment *readAtt =
99 &readFb->Attachment[att_index];
100 struct blit_state *blit = &ctx->Meta->Blit;
101 struct fb_tex_blit_state fb_tex_blit;
102 const GLint dstX = MIN2(dstX0, dstX1);
103 const GLint dstY = MIN2(dstY0, dstY1);
104 const GLint dstW = abs(dstX1 - dstX0);
105 const GLint dstH = abs(dstY1 - dstY0);
106 const int srcW = abs(srcX1 - srcX0);
107 const int srcH = abs(srcY1 - srcY0);
108 struct gl_texture_object *texObj;
109 GLuint srcLevel;
110 GLenum target;
111 struct gl_renderbuffer *rb = readAtt->Renderbuffer;
112 struct temp_texture *meta_temp_texture;
113
114 assert(rb->NumSamples == 0);
115
116 _mesa_meta_fb_tex_blit_begin(ctx, &fb_tex_blit);
117
118 if (readAtt->Texture &&
119 (readAtt->Texture->Target == GL_TEXTURE_2D ||
120 readAtt->Texture->Target == GL_TEXTURE_RECTANGLE)) {
121 /* If there's a texture attached of a type we can handle, then just use
122 * it directly.
123 */
124 srcLevel = readAtt->TextureLevel;
125 texObj = readAtt->Texture;
126 } else if (!readAtt->Texture && ctx->Driver.BindRenderbufferTexImage) {
127 texObj = texture_object_from_renderbuffer(ctx, rb);
128 if (texObj == NULL)
129 return false;
130
131 fb_tex_blit.temp_tex_obj = texObj;
132
133 srcLevel = 0;
134 if (_mesa_is_winsys_fbo(readFb)) {
135 GLint temp = srcY0;
136 srcY0 = rb->Height - srcY1;
137 srcY1 = rb->Height - temp;
138 flipY = -flipY;
139 }
140 } else {
141 GLenum tex_base_format;
142 /* Fall back to doing a CopyTexSubImage to get the destination
143 * renderbuffer into a texture.
144 */
145 if (ctx->Meta->Blit.no_ctsi_fallback)
146 return false;
147
148 if (do_depth) {
149 meta_temp_texture = _mesa_meta_get_temp_depth_texture(ctx);
150 tex_base_format = GL_DEPTH_COMPONENT;
151 } else {
152 meta_temp_texture = _mesa_meta_get_temp_texture(ctx);
153 tex_base_format =
154 _mesa_base_tex_format(ctx, rb->InternalFormat);
155 }
156
157 srcLevel = 0;
158 texObj = meta_temp_texture->tex_obj;
159 if (texObj == NULL) {
160 return false;
161 }
162
163 _mesa_meta_setup_copypix_texture(ctx, meta_temp_texture,
164 srcX0, srcY0,
165 srcW, srcH,
166 tex_base_format,
167 filter);
168
169 assert(texObj->Target == meta_temp_texture->Target);
170
171 srcX0 = 0;
172 srcY0 = 0;
173 srcX1 = srcW;
174 srcY1 = srcH;
175 }
176
177 target = texObj->Target;
178 fb_tex_blit.tex_obj = texObj;
179 fb_tex_blit.baseLevelSave = texObj->BaseLevel;
180 fb_tex_blit.maxLevelSave = texObj->MaxLevel;
181 fb_tex_blit.stencilSamplingSave = texObj->StencilSampling;
182
183 if (glsl_version) {
184 setup_glsl_blit_framebuffer(ctx, blit, drawFb, rb, target, do_depth);
185 }
186 else {
187 _mesa_meta_setup_ff_tnl_for_blit(ctx,
188 &ctx->Meta->Blit.VAO,
189 &ctx->Meta->Blit.buf_obj,
190 2);
191 }
192
193 /*
194 printf("Blit from texture!\n");
195 printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt);
196 printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture);
197 */
198
199 fb_tex_blit.samp_obj = setup_sampler(ctx, texObj, target, filter, srcLevel);
200
201 if (ctx->Extensions.EXT_texture_sRGB_decode) {
202 /* The GL 4.4 spec, section 18.3.1 ("Blitting Pixel Rectangles") says:
203 *
204 * "When values are taken from the read buffer, if FRAMEBUFFER_SRGB
205 * is enabled and the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
206 * for the framebuffer attachment corresponding to the read buffer
207 * is SRGB (see section 9.2.3), the red, green, and blue components
208 * are converted from the non-linear sRGB color space according to
209 * equation 3.24.
210 *
211 * When values are written to the draw buffers, blit operations
212 * bypass most of the fragment pipeline. The only fragment
213 * operations which affect a blit are the pixel ownership test,
214 * the scissor test, and sRGB conversion (see section 17.3.9)."
215 *
216 * ES 3.0 contains nearly the exact same text, but omits the part
217 * about GL_FRAMEBUFFER_SRGB as that doesn't exist in ES. Mesa
218 * defaults it to on for ES contexts, so we can safely check it.
219 */
220 const bool decode =
221 ctx->Color.sRGBEnabled && _mesa_is_format_srgb(rb->Format);
222
223 _mesa_set_sampler_srgb_decode(ctx, fb_tex_blit.samp_obj,
224 decode ? GL_DECODE_EXT
225 : GL_SKIP_DECODE_EXT);
226 }
227
228 if (!glsl_version) {
229 _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
230 _mesa_set_enable(ctx, target, GL_TRUE);
231 }
232
233 /* Prepare vertex data (the VBO was previously created and bound) */
234 {
235 struct vertex verts[4];
236 GLfloat s0, t0, s1, t1;
237
238 if (target == GL_TEXTURE_2D) {
239 const struct gl_texture_image *texImage
240 = _mesa_select_tex_image(texObj, target, srcLevel);
241 s0 = srcX0 / (float) texImage->Width;
242 s1 = srcX1 / (float) texImage->Width;
243 t0 = srcY0 / (float) texImage->Height;
244 t1 = srcY1 / (float) texImage->Height;
245 }
246 else {
247 assert(target == GL_TEXTURE_RECTANGLE_ARB);
248 s0 = (float) srcX0;
249 s1 = (float) srcX1;
250 t0 = (float) srcY0;
251 t1 = (float) srcY1;
252 }
253
254 /* Silence valgrind warnings about reading uninitialized stack. */
255 memset(verts, 0, sizeof(verts));
256
257 /* setup vertex positions */
258 verts[0].x = -1.0F * flipX;
259 verts[0].y = -1.0F * flipY;
260 verts[1].x = 1.0F * flipX;
261 verts[1].y = -1.0F * flipY;
262 verts[2].x = 1.0F * flipX;
263 verts[2].y = 1.0F * flipY;
264 verts[3].x = -1.0F * flipX;
265 verts[3].y = 1.0F * flipY;
266
267 verts[0].tex[0] = s0;
268 verts[0].tex[1] = t0;
269 verts[0].tex[2] = readAtt->Zoffset;
270 verts[1].tex[0] = s1;
271 verts[1].tex[1] = t0;
272 verts[1].tex[2] = readAtt->Zoffset;
273 verts[2].tex[0] = s1;
274 verts[2].tex[1] = t1;
275 verts[2].tex[2] = readAtt->Zoffset;
276 verts[3].tex[0] = s0;
277 verts[3].tex[1] = t1;
278 verts[3].tex[2] = readAtt->Zoffset;
279
280 _mesa_buffer_sub_data(ctx, blit->buf_obj, 0, sizeof(verts), verts);
281 }
282
283 /* setup viewport */
284 _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
285 _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth);
286 _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth);
287 _mesa_DepthMask(do_depth);
288 _mesa_DepthFunc(GL_ALWAYS);
289
290 _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
291 _mesa_meta_fb_tex_blit_end(ctx, target, &fb_tex_blit);
292
293 return true;
294 }
295
296 void
_mesa_meta_fb_tex_blit_begin(struct gl_context * ctx,struct fb_tex_blit_state * blit)297 _mesa_meta_fb_tex_blit_begin(struct gl_context *ctx,
298 struct fb_tex_blit_state *blit)
299 {
300 /* None of the existing callers preinitialize fb_tex_blit_state to zeros,
301 * and both use stack variables. If samp_obj_save is not NULL,
302 * _mesa_reference_sampler_object will try to dereference it. Leaving
303 * random garbage in samp_obj_save can only lead to crashes.
304 *
305 * Since the state isn't persistent across calls, we won't catch ref
306 * counting problems.
307 */
308 blit->samp_obj_save = NULL;
309 _mesa_reference_sampler_object(ctx, &blit->samp_obj_save,
310 ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler);
311 blit->temp_tex_obj = NULL;
312 }
313
314 void
_mesa_meta_fb_tex_blit_end(struct gl_context * ctx,GLenum target,struct fb_tex_blit_state * blit)315 _mesa_meta_fb_tex_blit_end(struct gl_context *ctx, GLenum target,
316 struct fb_tex_blit_state *blit)
317 {
318 struct gl_texture_object *const texObj =
319 _mesa_get_current_tex_object(ctx, target);
320
321 /* Either there is no temporary texture or the temporary texture is bound. */
322 assert(blit->temp_tex_obj == NULL || blit->temp_tex_obj == texObj);
323
324 /* Restore texture object state, the texture binding will be restored by
325 * _mesa_meta_end(). If the texture is the temporary texture that is about
326 * to be destroyed, don't bother restoring its state.
327 */
328 if (blit->temp_tex_obj == NULL) {
329 /* If the target restricts values for base level or max level, we assume
330 * that the original values were valid.
331 */
332 if (blit->baseLevelSave != texObj->BaseLevel)
333 _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_BASE_LEVEL,
334 &blit->baseLevelSave, false);
335
336 if (blit->maxLevelSave != texObj->MaxLevel)
337 _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
338 &blit->maxLevelSave, false);
339
340 /* If ARB_stencil_texturing is not supported, the mode won't have changed. */
341 if (texObj->StencilSampling != blit->stencilSamplingSave) {
342 /* GLint so the compiler won't complain about type signedness mismatch
343 * in the call to _mesa_texture_parameteriv below.
344 */
345 const GLint param = blit->stencilSamplingSave ?
346 GL_STENCIL_INDEX : GL_DEPTH_COMPONENT;
347
348 _mesa_texture_parameteriv(ctx, texObj, GL_DEPTH_STENCIL_TEXTURE_MODE,
349 ¶m, false);
350 }
351 }
352
353 _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, blit->samp_obj_save);
354 _mesa_reference_sampler_object(ctx, &blit->samp_obj_save, NULL);
355 _mesa_reference_sampler_object(ctx, &blit->samp_obj, NULL);
356 _mesa_delete_nameless_texture(ctx, blit->temp_tex_obj);
357 }
358
359 static struct gl_texture_object *
texture_object_from_renderbuffer(struct gl_context * ctx,struct gl_renderbuffer * rb)360 texture_object_from_renderbuffer(struct gl_context *ctx,
361 struct gl_renderbuffer *rb)
362 {
363 struct gl_texture_image *texImage;
364 struct gl_texture_object *texObj;
365 const GLenum target = GL_TEXTURE_2D;
366
367 texObj = ctx->Driver.NewTextureObject(ctx, 0xDEADBEEF, target);
368 texImage = _mesa_get_tex_image(ctx, texObj, target, 0);
369
370 if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
371 _mesa_delete_nameless_texture(ctx, texObj);
372 return NULL;
373 }
374
375 if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
376 rb->NeedsFinishRenderTexture = true;
377 ctx->Driver.FinishRenderTexture(ctx, rb);
378 }
379
380 return texObj;
381 }
382
383 static struct gl_sampler_object *
setup_sampler(struct gl_context * ctx,struct gl_texture_object * texObj,GLenum target,GLenum filter,GLuint srcLevel)384 setup_sampler(struct gl_context *ctx, struct gl_texture_object *texObj,
385 GLenum target, GLenum filter, GLuint srcLevel)
386 {
387 struct gl_sampler_object *samp_obj =
388 ctx->Driver.NewSamplerObject(ctx, 0xDEADBEEF);
389
390 if (samp_obj == NULL)
391 return NULL;
392
393 _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj);
394 _mesa_set_sampler_filters(ctx, samp_obj, filter, filter);
395 _mesa_set_sampler_wrap(ctx, samp_obj, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE,
396 samp_obj->WrapR);
397
398 /* Prepare src texture state */
399 _mesa_bind_texture(ctx, target, texObj);
400 if (target != GL_TEXTURE_RECTANGLE_ARB) {
401 _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_BASE_LEVEL,
402 (GLint *) &srcLevel, false);
403 _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
404 (GLint *) &srcLevel, false);
405 }
406
407 return samp_obj;
408 }
409
410 /**
411 * Meta implementation of ctx->Driver.BlitFramebuffer() in terms
412 * of texture mapping and polygon rendering.
413 */
414 GLbitfield
_mesa_meta_BlitFramebuffer(struct gl_context * ctx,const struct gl_framebuffer * readFb,const struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)415 _mesa_meta_BlitFramebuffer(struct gl_context *ctx,
416 const struct gl_framebuffer *readFb,
417 const struct gl_framebuffer *drawFb,
418 GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
419 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
420 GLbitfield mask, GLenum filter)
421 {
422 const GLint dstW = abs(dstX1 - dstX0);
423 const GLint dstH = abs(dstY1 - dstY0);
424 const GLint dstFlipX = (dstX1 - dstX0) / dstW;
425 const GLint dstFlipY = (dstY1 - dstY0) / dstH;
426
427 struct {
428 GLint srcX0, srcY0, srcX1, srcY1;
429 GLint dstX0, dstY0, dstX1, dstY1;
430 } clip = {
431 srcX0, srcY0, srcX1, srcY1,
432 dstX0, dstY0, dstX1, dstY1
433 };
434
435 const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
436 ctx->Extensions.ARB_fragment_shader;
437
438 /* Multisample blit is not supported. */
439 if (readFb->Visual.samples > 0)
440 return mask;
441
442 /* Clip a copy of the blit coordinates. If these differ from the input
443 * coordinates, then we'll set the scissor.
444 */
445 if (!_mesa_clip_blit(ctx, readFb, drawFb,
446 &clip.srcX0, &clip.srcY0, &clip.srcX1, &clip.srcY1,
447 &clip.dstX0, &clip.dstY0, &clip.dstX1, &clip.dstY1)) {
448 /* clipped/scissored everything away */
449 return 0;
450 }
451
452 /* Only scissor and FRAMEBUFFER_SRGB affect blit. Leave sRGB alone, but
453 * save restore scissor as we'll set a custom scissor if necessary.
454 */
455 _mesa_meta_begin(ctx, MESA_META_ALL &
456 ~(MESA_META_DRAW_BUFFERS |
457 MESA_META_FRAMEBUFFER_SRGB));
458
459 /* Dithering shouldn't be performed for glBlitFramebuffer */
460 _mesa_set_enable(ctx, GL_DITHER, GL_FALSE);
461
462 /* If the clipping earlier changed the destination rect at all, then
463 * enable the scissor to clip to it.
464 */
465 if (clip.dstX0 != dstX0 || clip.dstY0 != dstY0 ||
466 clip.dstX1 != dstX1 || clip.dstY1 != dstY1) {
467 _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
468 _mesa_Scissor(MIN2(clip.dstX0, clip.dstX1),
469 MIN2(clip.dstY0, clip.dstY1),
470 abs(clip.dstX0 - clip.dstX1),
471 abs(clip.dstY0 - clip.dstY1));
472 }
473
474 /* Try faster, direct texture approach first */
475 if (mask & GL_COLOR_BUFFER_BIT) {
476 if (blitframebuffer_texture(ctx, readFb, drawFb,
477 srcX0, srcY0, srcX1, srcY1,
478 dstX0, dstY0, dstX1, dstY1,
479 filter, dstFlipX, dstFlipY,
480 use_glsl_version, false)) {
481 mask &= ~GL_COLOR_BUFFER_BIT;
482 }
483 }
484
485 if (mask & GL_DEPTH_BUFFER_BIT && use_glsl_version) {
486 if (blitframebuffer_texture(ctx, readFb, drawFb,
487 srcX0, srcY0, srcX1, srcY1,
488 dstX0, dstY0, dstX1, dstY1,
489 filter, dstFlipX, dstFlipY,
490 use_glsl_version, true)) {
491 mask &= ~GL_DEPTH_BUFFER_BIT;
492 }
493 }
494
495 if (mask & GL_STENCIL_BUFFER_BIT) {
496 /* XXX can't easily do stencil */
497 }
498
499 _mesa_meta_end(ctx);
500
501 return mask;
502 }
503
504 void
_mesa_meta_glsl_blit_cleanup(struct gl_context * ctx,struct blit_state * blit)505 _mesa_meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit)
506 {
507 if (blit->VAO) {
508 _mesa_DeleteVertexArrays(1, &blit->VAO);
509 blit->VAO = 0;
510 _mesa_reference_buffer_object(ctx, &blit->buf_obj, NULL);
511 }
512
513 _mesa_meta_blit_shader_table_cleanup(ctx, &blit->shaders_with_depth);
514 _mesa_meta_blit_shader_table_cleanup(ctx, &blit->shaders_without_depth);
515
516 if (blit->depthTex.tex_obj != NULL) {
517 _mesa_delete_nameless_texture(ctx, blit->depthTex.tex_obj);
518 blit->depthTex.tex_obj = NULL;
519 }
520 }
521
522 void
_mesa_meta_and_swrast_BlitFramebuffer(struct gl_context * ctx,struct gl_framebuffer * readFb,struct gl_framebuffer * drawFb,GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)523 _mesa_meta_and_swrast_BlitFramebuffer(struct gl_context *ctx,
524 struct gl_framebuffer *readFb,
525 struct gl_framebuffer *drawFb,
526 GLint srcX0, GLint srcY0,
527 GLint srcX1, GLint srcY1,
528 GLint dstX0, GLint dstY0,
529 GLint dstX1, GLint dstY1,
530 GLbitfield mask, GLenum filter)
531 {
532 mask = _mesa_meta_BlitFramebuffer(ctx, readFb, drawFb,
533 srcX0, srcY0, srcX1, srcY1,
534 dstX0, dstY0, dstX1, dstY1,
535 mask, filter);
536 if (mask == 0x0)
537 return;
538
539 _swrast_BlitFramebuffer(ctx, readFb, drawFb,
540 srcX0, srcY0, srcX1, srcY1,
541 dstX0, dstY0, dstX1, dstY1,
542 mask, filter);
543 }
544