/** A partial implementation of glCopyImageSubData * * This is a partial implementation of glCopyImageSubData that works only * if both textures are uncompressed and the destination texture is * renderable. It uses a slight abuse of a texture view (see make_view) to * turn the source texture into the destination texture type and then uses * _mesa_meta_BlitFramebuffers to do the copy. */ bool _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx, struct gl_texture_image *src_tex_image, struct gl_renderbuffer *src_renderbuffer, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, struct gl_renderbuffer *dst_renderbuffer, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { mesa_format src_format, dst_format; GLint src_internal_format, dst_internal_format; GLuint src_view_texture = 0; struct gl_texture_image *src_view_tex_image; struct gl_framebuffer *readFb; struct gl_framebuffer *drawFb = NULL; bool success = false; GLbitfield mask; GLenum status, attachment; if (src_renderbuffer) { src_format = src_renderbuffer->Format; src_internal_format = src_renderbuffer->InternalFormat; } else { assert(src_tex_image); src_format = src_tex_image->TexFormat; src_internal_format = src_tex_image->InternalFormat; } if (dst_renderbuffer) { dst_format = dst_renderbuffer->Format; dst_internal_format = dst_renderbuffer->InternalFormat; } else { assert(dst_tex_image); dst_format = dst_tex_image->TexFormat; dst_internal_format = dst_tex_image->InternalFormat; } if (_mesa_is_format_compressed(src_format)) return false; if (_mesa_is_format_compressed(dst_format)) return false; if (src_internal_format == dst_internal_format) { src_view_tex_image = src_tex_image; } else { if (src_renderbuffer) { assert(src_tex_image == NULL); src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer); } if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture, dst_internal_format)) goto cleanup; } /* We really only need to stash the bound framebuffers and scissor. */ _mesa_meta_begin(ctx, MESA_META_SCISSOR); readFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (readFb == NULL) goto meta_end; drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (drawFb == NULL) goto meta_end; _mesa_bind_framebuffers(ctx, drawFb, readFb); switch (_mesa_get_format_base_format(src_format)) { case GL_DEPTH_COMPONENT: attachment = GL_DEPTH_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT; break; case GL_DEPTH_STENCIL: attachment = GL_DEPTH_STENCIL_ATTACHMENT; mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; break; case GL_STENCIL_INDEX: attachment = GL_STENCIL_ATTACHMENT; mask = GL_STENCIL_BUFFER_BIT; break; default: attachment = GL_COLOR_ATTACHMENT0; mask = GL_COLOR_BUFFER_BIT; _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0); } if (src_view_tex_image) { /* Prefer the tex image because, even if we have a renderbuffer, we may * have had to wrap it in a texture view. */ _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, attachment, src_view_tex_image, src_z); } else { _mesa_framebuffer_renderbuffer(ctx, ctx->ReadBuffer, attachment, src_renderbuffer); } status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; if (dst_renderbuffer) { _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, attachment, dst_renderbuffer); } else { _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, attachment, dst_tex_image, dst_z); } status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; /* Explicitly disable sRGB encoding */ ctx->DrawBuffer->Visual.sRGBCapable = false; /* Since we've bound a new draw framebuffer, we need to update its * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to * be correct. */ _mesa_update_state(ctx); /* We skip the core BlitFramebuffer checks for format consistency. * We have already created views to ensure that the texture formats * match. */ ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, src_x, src_y, src_x + src_width, src_y + src_height, dst_x, dst_y, dst_x + src_width, dst_y + src_height, mask, GL_NEAREST); success = true; meta_end: _mesa_reference_framebuffer(&readFb, NULL); _mesa_reference_framebuffer(&drawFb, NULL); _mesa_meta_end(ctx); cleanup: _mesa_DeleteTextures(1, &src_view_texture); /* If we got a renderbuffer source, delete the temporary texture */ if (src_renderbuffer && src_tex_image) ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject); return success; }
/** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, or texture borders. */ void _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct vertex verts[4]; const GLuint baseLevel = texObj->BaseLevel; const GLuint maxLevel = texObj->MaxLevel; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; GLenum faceTarget; GLuint dstLevel; struct gl_sampler_object *samp_obj_save = NULL; GLint swizzle[4]; GLboolean swizzleSaved = GL_FALSE; /* GLint so the compiler won't complain about type signedness mismatch in * the calls to _mesa_texture_parameteriv below. */ static const GLint always_false = GL_FALSE; static const GLint always_true = GL_TRUE; if (fallback_required(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); return; } if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { faceTarget = target; target = GL_TEXTURE_CUBE_MAP; } else { faceTarget = target; } _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS); _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); /* Choose between glsl version and fixed function version of * GenerateMipmap function. */ if (use_glsl_version) { _mesa_meta_setup_vertex_objects(ctx, &mipmap->VAO, &mipmap->buf_obj, true, 2, 4, 0); _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders); } else { _mesa_meta_setup_ff_tnl_for_blit(ctx, &mipmap->VAO, &mipmap->buf_obj, 3); _mesa_set_enable(ctx, target, GL_TRUE); } _mesa_reference_sampler_object(ctx, &samp_obj_save, ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler); /* We may have been called from glGenerateTextureMipmap with CurrentUnit * still set to 0, so we don't know when we can skip binding the texture. * Assume that _mesa_BindTexture will be fast if we're rebinding the same * texture. */ _mesa_BindTexture(target, texObj->Name); if (mipmap->samp_obj == NULL) { mipmap->samp_obj = ctx->Driver.NewSamplerObject(ctx, 0xDEADBEEF); if (mipmap->samp_obj == NULL) { /* This is a bit lazy. Flag out of memory, and then don't bother to * clean up. Once out of memory is flagged, the only realistic next * move is to destroy the context. That will trigger all the right * clean up. */ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenerateMipmap"); return; } _mesa_set_sampler_filters(ctx, mipmap->samp_obj, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); _mesa_set_sampler_wrap(ctx, mipmap->samp_obj, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); /* We don't want to encode or decode sRGB values; treat them as linear. */ _mesa_set_sampler_srgb_decode(ctx, mipmap->samp_obj, GL_SKIP_DECODE_EXT); } _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, mipmap->samp_obj); assert(mipmap->fb != NULL); _mesa_bind_framebuffers(ctx, mipmap->fb, mipmap->fb); _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_false, false); if (texObj->_Swizzle != SWIZZLE_NOOP) { static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; memcpy(swizzle, texObj->Swizzle, sizeof(swizzle)); swizzleSaved = GL_TRUE; _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop, false); } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F; verts[0].y = -1.0F; verts[1].x = 1.0F; verts[1].y = -1.0F; verts[2].x = 1.0F; verts[2].y = 1.0F; verts[3].x = -1.0F; verts[3].y = 1.0F; /* texture is already locked, unlock now */ _mesa_unlock_texture(ctx, texObj); _mesa_prepare_mipmap_levels(ctx, texObj, baseLevel, maxLevel); for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; const GLuint srcLevel = dstLevel - 1; GLuint layer; GLsizei srcWidth, srcHeight, srcDepth; GLsizei dstWidth, dstHeight, dstDepth; srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel); assert(srcImage->Border == 0); /* src size */ srcWidth = srcImage->Width; if (target == GL_TEXTURE_1D_ARRAY) { srcHeight = 1; srcDepth = srcImage->Height; } else { srcHeight = srcImage->Height; srcDepth = srcImage->Depth; } /* new dst size */ dstWidth = minify(srcWidth, 1); dstHeight = minify(srcHeight, 1); dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth; if (dstWidth == srcWidth && dstHeight == srcHeight && dstDepth == srcDepth) { /* all done */ break; } /* Allocate storage for the destination mipmap image(s) */ /* Set MaxLevel large enough to hold the new level when we allocate it */ _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, (GLint *) &dstLevel, false); dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); /* All done. We either ran out of memory or we would go beyond the last * valid level of an immutable texture if we continued. */ if (dstImage == NULL) break; /* limit minification to src level */ _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, (GLint *) &srcLevel, false); /* setup viewport */ _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); for (layer = 0; layer < dstDepth; ++layer) { /* Setup texture coordinates */ _mesa_meta_setup_texture_coords(faceTarget, layer, 0, 0, /* xoffset, yoffset */ srcWidth, srcHeight, /* img size */ srcWidth, srcHeight, srcDepth, verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ _mesa_buffer_data(ctx, mipmap->buf_obj, GL_NONE, sizeof(verts), verts, GL_DYNAMIC_DRAW, __func__); _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (_mesa_check_framebuffer_status(ctx, ctx->DrawBuffer) != GL_FRAMEBUFFER_COMPLETE) { _mesa_problem(ctx, "Unexpected incomplete framebuffer in " "_mesa_meta_GenerateMipmap()"); break; } assert(dstWidth == ctx->DrawBuffer->Width); if (target == GL_TEXTURE_1D_ARRAY) { assert(dstHeight == 1); } else { assert(dstHeight == ctx->DrawBuffer->Height); } _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } } _mesa_lock_texture(ctx, texObj); /* relock */ _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj_save); _mesa_reference_sampler_object(ctx, &samp_obj_save, NULL); _mesa_meta_end(ctx); _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, &maxLevelSave, false); if (genMipmapSave) _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_true, false); if (swizzleSaved) _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzle, false); }
bool _mesa_meta_pbo_TexSubImage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *tex_image, int xoffset, int yoffset, int zoffset, int width, int height, int depth, GLenum format, GLenum type, const void *pixels, bool create_pbo, const struct gl_pixelstore_attrib *packing) { struct gl_buffer_object *pbo = NULL; GLuint pbo_tex = 0; struct gl_framebuffer *readFb = NULL; struct gl_framebuffer *drawFb = NULL; int image_height; struct gl_texture_image *pbo_tex_image; GLenum status; bool success = false; int z; if (!_mesa_is_bufferobj(packing->BufferObj) && (!create_pbo || pixels == NULL)) return false; if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX || format == GL_COLOR_INDEX) return false; if (ctx->_ImageTransferState) return false; /* This function rely on BlitFramebuffer to fill in the pixel data for * glTex[Sub]Image*D. But, BlitFrameBuffer doesn't support signed to * unsigned or unsigned to signed integer conversions. */ if (need_signed_unsigned_int_conversion(tex_image->TexFormat, format, type)) return false; /* For arrays, use a tall (height * depth) 2D texture but taking into * account the inter-image padding specified with the image height packing * property. */ image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight; _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER | MESA_META_PIXEL_STORE)); pbo_tex_image = create_texture_for_pbo(ctx, create_pbo, GL_PIXEL_UNPACK_BUFFER, dims, width, height, depth, format, type, pixels, packing, &pbo, &pbo_tex); if (!pbo_tex_image) { _mesa_meta_end(ctx); return false; } readFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (readFb == NULL) goto fail; drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (drawFb == NULL) goto fail; _mesa_bind_framebuffers(ctx, drawFb, tex_image ? readFb : ctx->ReadBuffer); if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) { assert(depth == 1); assert(zoffset == 0); depth = height; height = 1; image_height = 1; zoffset = yoffset; yoffset = 0; } _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, GL_COLOR_ATTACHMENT0, pbo_tex_image, 0); /* If this passes on the first layer it should pass on the others */ status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, tex_image, zoffset); /* If this passes on the first layer it should pass on the others */ status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; /* Explicitly disable sRGB encoding */ ctx->DrawBuffer->Visual.sRGBCapable = false; _mesa_update_state(ctx); if (_mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, 0, 0, width, height, xoffset, yoffset, xoffset + width, yoffset + height, GL_COLOR_BUFFER_BIT, GL_NEAREST)) goto fail; for (z = 1; z < depth; z++) { _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, tex_image, zoffset + z); _mesa_update_state(ctx); _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, 0, z * image_height, width, z * image_height + height, xoffset, yoffset, xoffset + width, yoffset + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); } success = true; fail: _mesa_reference_framebuffer(&readFb, NULL); _mesa_reference_framebuffer(&drawFb, NULL); _mesa_DeleteTextures(1, &pbo_tex); _mesa_reference_buffer_object(ctx, &pbo, NULL); _mesa_meta_end(ctx); return success; }
bool _mesa_meta_pbo_GetTexSubImage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *tex_image, int xoffset, int yoffset, int zoffset, int width, int height, int depth, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing) { struct gl_buffer_object *pbo = NULL; GLuint pbo_tex = 0; struct gl_framebuffer *readFb; struct gl_framebuffer *drawFb; int image_height; struct gl_texture_image *pbo_tex_image; struct gl_renderbuffer *rb = NULL; GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format); GLenum status, src_base_format; bool success = false, clear_channels_to_zero = false; float save_clear_color[4]; int z; if (!_mesa_is_bufferobj(packing->BufferObj)) return false; if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL || format == GL_STENCIL_INDEX || format == GL_COLOR_INDEX) return false; /* Don't use meta path for readpixels in below conditions. */ if (!tex_image) { rb = ctx->ReadBuffer->_ColorReadBuffer; /* _mesa_get_readpixels_transfer_ops() includes the cases of read * color clamping along with the ctx->_ImageTransferState. */ if (_mesa_get_readpixels_transfer_ops(ctx, rb->Format, format, type, GL_FALSE)) return false; if (_mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat, dstBaseFormat)) return false; /* This function rely on BlitFramebuffer to fill in the pixel data for * ReadPixels. But, BlitFrameBuffer doesn't support signed to unsigned * or unsigned to signed integer conversions. OpenGL spec expects an * invalid operation in that case. */ if (need_signed_unsigned_int_conversion(rb->Format, format, type)) return false; } else { if (need_signed_unsigned_int_conversion(tex_image->TexFormat, format, type)) return false; } /* For arrays, use a tall (height * depth) 2D texture but taking into * account the inter-image padding specified with the image height packing * property. */ image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight; _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER | MESA_META_PIXEL_STORE)); pbo_tex_image = create_texture_for_pbo(ctx, false, GL_PIXEL_PACK_BUFFER, dims, width, height, depth, format, type, pixels, packing, &pbo, &pbo_tex); if (!pbo_tex_image) { _mesa_meta_end(ctx); return false; } /* GL_CLAMP_FRAGMENT_COLOR doesn't affect ReadPixels and GettexImage */ if (ctx->Extensions.ARB_color_buffer_float) _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); readFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (readFb == NULL) goto fail; drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (drawFb == NULL) goto fail; if (tex_image && tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) { assert(depth == 1); assert(zoffset == 0); depth = height; height = 1; image_height = 1; zoffset = yoffset; yoffset = 0; } /* If we were given a texture, bind it to the read framebuffer. If not, * we're doing a ReadPixels and we should just use whatever framebuffer * the client has bound. */ _mesa_bind_framebuffers(ctx, drawFb, tex_image ? readFb : ctx->ReadBuffer); if (tex_image) { _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, GL_COLOR_ATTACHMENT0, tex_image, zoffset); /* If this passes on the first layer it should pass on the others */ status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; } else { assert(depth == 1); } _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, pbo_tex_image, 0); /* If this passes on the first layer it should pass on the others */ status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; /* Explicitly disable sRGB encoding */ ctx->DrawBuffer->Visual.sRGBCapable = false; _mesa_update_state(ctx); if (_mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, xoffset, yoffset, xoffset + width, yoffset + height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)) goto fail; src_base_format = tex_image ? tex_image->_BaseFormat : ctx->ReadBuffer->_ColorReadBuffer->_BaseFormat; /* Depending on the base formats involved we might need to rebase some * values. For example if we download from a Luminance format to RGBA * format, we want G=0 and B=0. */ clear_channels_to_zero = _mesa_need_luminance_to_rgb_conversion(src_base_format, pbo_tex_image->_BaseFormat); if (clear_channels_to_zero) { memcpy(save_clear_color, ctx->Color.ClearColor.f, 4 * sizeof(float)); /* Clear the Green, Blue channels. */ _mesa_ColorMask(GL_FALSE, GL_TRUE, GL_TRUE, src_base_format != GL_LUMINANCE_ALPHA); _mesa_ClearColor(0.0, 0.0, 0.0, 1.0); _mesa_Clear(GL_COLOR_BUFFER_BIT); } for (z = 1; z < depth; z++) { _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, GL_COLOR_ATTACHMENT0, tex_image, zoffset + z); _mesa_update_state(ctx); _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, xoffset, yoffset, xoffset + width, yoffset + height, 0, z * image_height, width, z * image_height + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (clear_channels_to_zero) _mesa_Clear(GL_COLOR_BUFFER_BIT); } /* Unmask the color channels and restore the saved clear color values. */ if (clear_channels_to_zero) { _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); _mesa_ClearColor(save_clear_color[0], save_clear_color[1], save_clear_color[2], save_clear_color[3]); } success = true; fail: _mesa_reference_framebuffer(&drawFb, NULL); _mesa_reference_framebuffer(&readFb, NULL); _mesa_DeleteTextures(1, &pbo_tex); _mesa_reference_buffer_object(ctx, &pbo, NULL); _mesa_meta_end(ctx); return success; }
void brw_meta_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt) { struct gl_context *ctx = &brw->ctx; struct gl_framebuffer *drawFb; struct gl_renderbuffer *rb; struct rect rect; brw_emit_mi_flush(brw); drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); if (drawFb == NULL) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "in %s", __func__); return; } _mesa_meta_begin(ctx, MESA_META_ALL); rb = brw_get_rb_for_slice(brw, mt, 0, 0, false); _mesa_bind_framebuffers(ctx, drawFb, ctx->ReadBuffer); _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0, rb); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); brw_fast_clear_init(brw); use_rectlist(brw, true); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); /* SKL+ also has a resolve mode for compressed render targets and thus more * bits to let us select the type of resolve. For fast clear resolves, it * turns out we can use the same value as pre-SKL though. */ if (intel_miptree_is_lossless_compressed(brw, mt)) set_fast_clear_op(brw, GEN9_PS_RENDER_TARGET_RESOLVE_FULL); else set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE); mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED; get_resolve_rect(brw, mt, &rect); brw_draw_rectlist(brw, &rect, 1); set_fast_clear_op(brw, 0); use_rectlist(brw, false); _mesa_reference_renderbuffer(&rb, NULL); _mesa_reference_framebuffer(&drawFb, NULL); _mesa_meta_end(ctx); /* We're typically called from intel_update_state() and we're supposed to * return with the state all updated to what it was before * brw_meta_resolve_color() was called. The meta rendering will have * messed up the state and we need to call _mesa_update_state() again to * get back to where we were supposed to be when resolve was called. */ if (ctx->NewState) _mesa_update_state(ctx); }