/** * Implementation of up or downsampling for window-system MSAA miptrees. */ void brw_meta_updownsample(struct brw_context *brw, struct intel_mipmap_tree *src_mt, struct intel_mipmap_tree *dst_mt) { struct gl_context *ctx = &brw->ctx; GLuint fbos[2], src_rbo, dst_rbo, src_fbo, dst_fbo; GLenum drawbuffer; GLbitfield attachment, blit_bit; if (_mesa_get_format_base_format(src_mt->format) == GL_DEPTH_COMPONENT || _mesa_get_format_base_format(src_mt->format) == GL_DEPTH_STENCIL) { attachment = GL_DEPTH_ATTACHMENT; drawbuffer = GL_NONE; blit_bit = GL_DEPTH_BUFFER_BIT; } else { attachment = GL_COLOR_ATTACHMENT0; drawbuffer = GL_COLOR_ATTACHMENT0; blit_bit = GL_COLOR_BUFFER_BIT; } brw_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(2, fbos); src_rbo = brw_get_rb_for_slice(brw, src_mt, 0, 0, false); dst_rbo = brw_get_rb_for_slice(brw, dst_mt, 0, 0, false); src_fbo = fbos[0]; dst_fbo = fbos[1]; _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, src_fbo); _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, src_rbo); _mesa_ReadBuffer(drawbuffer); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fbo); _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, dst_rbo); _mesa_DrawBuffer(drawbuffer); _mesa_BlitFramebuffer(0, 0, src_mt->logical_width0, src_mt->logical_height0, 0, 0, dst_mt->logical_width0, dst_mt->logical_height0, blit_bit, GL_NEAREST); _mesa_DeleteRenderbuffers(1, &src_rbo); _mesa_DeleteRenderbuffers(1, &dst_rbo); _mesa_DeleteFramebuffers(2, fbos); _mesa_meta_end(ctx); brw_emit_mi_flush(brw); }
/** * The ClearBuffer framework is so complicated and so riddled with the * assumption that the framebuffer is bound that, for now, we will just fake * direct state access clearing for the user. */ void GLAPIENTRY _mesa_ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLfloat depth, GLint stencil) { GLint oldfb; _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); _mesa_ClearBufferfi(buffer, 0, depth, stencil); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); }
/** * The ClearBuffer framework is so complicated and so riddled with the * assumption that the framebuffer is bound that, for now, we will just fake * direct state access clearing for the user. */ void GLAPIENTRY _mesa_ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value) { GLint oldfb; _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); _mesa_ClearBufferfv(buffer, drawbuffer, value); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); }
void brw_meta_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt) { struct gl_context *ctx = &brw->ctx; GLuint fbo; struct gl_renderbuffer *rb; struct rect rect; brw_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(1, &fbo); rb = brw_get_rb_for_slice(brw, mt, 0, 0, false); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); _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_DeleteFramebuffers(1, &fbo); _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); }
void brw_meta_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt) { struct gl_context *ctx = &brw->ctx; GLuint fbo, rbo; struct rect rect; intel_batchbuffer_emit_mi_flush(brw); _mesa_meta_begin(ctx, MESA_META_ALL); _mesa_GenFramebuffers(1, &fbo); rbo = brw_get_rb_for_slice(brw, mt, 0, 0, false); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); brw_fast_clear_init(brw); use_rectlist(brw, true); brw_bind_rep_write_shader(brw, (float *) fast_clear_color); 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(ctx, &rect, 1); set_fast_clear_op(brw, 0); use_rectlist(brw, false); _mesa_DeleteRenderbuffers(1, &rbo); _mesa_DeleteFramebuffers(1, &fbo); _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); }
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) { GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 }; int full_height, image_height; struct gl_texture_image *pbo_tex_image; struct gl_renderbuffer *rb = NULL; GLenum status; bool success = false; 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; if (ctx->_ImageTransferState) return false; if (!tex_image) { rb = ctx->ReadBuffer->_ColorReadBuffer; if (_mesa_need_rgb_to_luminance_conversion(rb->Format, format)) 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; full_height = image_height * (depth - 1) + height; pbo_tex_image = create_texture_for_pbo(ctx, false, GL_PIXEL_PACK_BUFFER, width, full_height * depth, format, type, pixels, packing, &pbo, &pbo_tex); if (!pbo_tex_image) return false; _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER | MESA_META_PIXEL_STORE)); _mesa_GenFramebuffers(2, fbos); 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. */ if (tex_image) { _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_image, zoffset); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; } else { assert(depth == 1); } _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pbo_tex_image, 0); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; _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; for (z = 1; z < depth; z++) { _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, 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); } success = true; fail: _mesa_DeleteFramebuffers(2, fbos); _mesa_DeleteTextures(1, &pbo_tex); _mesa_DeleteBuffers(1, &pbo); _mesa_meta_end(ctx); return success; }
/** 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; GLuint fbos[2]; 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_tex_image->InternalFormat)) goto cleanup; } /* We really only need to stash the bound framebuffers and scissor. */ _mesa_meta_begin(ctx, MESA_META_SCISSOR); _mesa_GenFramebuffers(2, fbos); _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); 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_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment, src_view_tex_image, src_z); } else { _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, src_renderbuffer->Name); } status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; if (dst_renderbuffer) { _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, dst_renderbuffer->Name); } else { _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment, dst_tex_image, dst_z); } status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; /* 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_DeleteFramebuffers(2, fbos); _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; }
/** * Check if the call to _mesa_meta_GenerateMipmap() will require a * software fallback. The fallback path will require that the texture * images are mapped. * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise */ static bool fallback_required(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { const GLuint fboSave = ctx->DrawBuffer->Name; struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct gl_texture_image *baseImage; GLuint srcLevel; GLenum status; /* check for fallbacks */ if (target == GL_TEXTURE_3D) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() to %s target\n", _mesa_lookup_enum_by_nr(target)); return true; } srcLevel = texObj->BaseLevel; baseImage = _mesa_select_tex_image(texObj, target, srcLevel); if (!baseImage) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() couldn't find base teximage\n"); return true; } if (_mesa_is_format_compressed(baseImage->TexFormat)) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() with %s format\n", _mesa_get_format_name(baseImage->TexFormat)); return true; } if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB && !ctx->Extensions.EXT_texture_sRGB_decode) { /* The texture format is sRGB but we can't turn off sRGB->linear * texture sample conversion. So we won't be able to generate the * right colors when rendering. Need to use a fallback. */ _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() of sRGB texture without " "sRGB decode\n"); return true; } /* * Test that we can actually render in the texture's format. */ if (!mipmap->FBO) _mesa_GenFramebuffers(1, &mipmap->FBO); _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, baseImage, 0); status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() got incomplete FBO\n"); return true; } return false; }
/** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, 1D/2D array 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 GLuint currentTexUnitSave = ctx->Texture.CurrentUnit; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; GLenum faceTarget; GLuint dstLevel; GLuint samplerSave; GLint swizzle[4]; GLboolean swizzleSaved = GL_FALSE; 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); /* Choose between glsl version and fixed function version of * GenerateMipmap function. */ if (use_glsl_version) { _mesa_meta_setup_vertex_objects(&mipmap->VAO, &mipmap->VBO, true, 2, 4, 0); _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders); } else { _mesa_meta_setup_ff_tnl_for_blit(&mipmap->VAO, &mipmap->VBO, 3); _mesa_set_enable(ctx, target, GL_TRUE); } samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; if (currentTexUnitSave != 0) _mesa_BindTexture(target, texObj->Name); if (!mipmap->Sampler) { _mesa_GenSamplers(1, &mipmap->Sampler); _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); /* We don't want to encode or decode sRGB values; treat them as linear. * This is not technically correct for GLES3 but we don't get any API * error at the moment. */ if (ctx->Extensions.EXT_texture_sRGB_decode) { _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); } } else { _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); } assert(mipmap->FBO != 0); _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_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_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop); } /* 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); 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_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); if (!prepare_mipmap_level(ctx, texObj, dstLevel, dstWidth, dstHeight, dstDepth, srcImage->InternalFormat, srcImage->TexFormat)) { /* All done. We either ran out of memory or we would go beyond the * last valid level of an immutable texture if we continued. */ break; } dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); /* limit minification to src level */ _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); /* 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, 1, /* width, height never used here */ verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, GL_DYNAMIC_DRAW_ARB); _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (_mesa_CheckFramebufferStatus(GL_FRAMEBUFFER) != 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_BindSampler(ctx->Texture.CurrentUnit, samplerSave); _mesa_meta_end(ctx); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); if (genMipmapSave) _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); if (swizzleSaved) _mesa_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); }
/** 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, int src_x, int src_y, int src_z, struct gl_texture_image *dst_tex_image, int dst_x, int dst_y, int dst_z, int src_width, int src_height) { GLuint src_view_texture = 0; struct gl_texture_image *src_view_tex_image; GLuint fbos[2]; bool success = false; GLbitfield mask; GLenum status, attachment; if (_mesa_is_format_compressed(dst_tex_image->TexFormat)) return false; if (_mesa_is_format_compressed(src_tex_image->TexFormat)) return false; if (src_tex_image->InternalFormat == dst_tex_image->InternalFormat) { src_view_tex_image = src_tex_image; } else { if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture, dst_tex_image->InternalFormat)) goto cleanup; } /* We really only need to stash the bound framebuffers. */ _mesa_meta_begin(ctx, 0); _mesa_GenFramebuffers(2, fbos); _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); switch (_mesa_get_format_base_format(src_tex_image->TexFormat)) { 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); } _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment, src_view_tex_image, src_z); status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment, dst_tex_image, dst_z); status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto meta_end; /* 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, 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_DeleteFramebuffers(2, fbos); _mesa_meta_end(ctx); cleanup: _mesa_DeleteTextures(1, &src_view_texture); return success; }
/** * Check if the call to _mesa_meta_GenerateMipmap() will require a * software fallback. The fallback path will require that the texture * images are mapped. * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise */ static bool fallback_required(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { const GLuint fboSave = ctx->DrawBuffer->Name; struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct gl_texture_image *baseImage; GLuint srcLevel; GLenum status; /* GL_DRAW_FRAMEBUFFER does not exist in OpenGL ES 1.x, and since * _mesa_meta_begin hasn't been called yet, we have to work-around API * difficulties. The whole reason that GL_DRAW_FRAMEBUFFER is used instead * of GL_FRAMEBUFFER is that the read framebuffer may be different. This * is moot in OpenGL ES 1.x. */ const GLenum fbo_target = ctx->API == API_OPENGLES ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER; /* check for fallbacks */ if (target == GL_TEXTURE_3D) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() to %s target\n", _mesa_enum_to_string(target)); return true; } srcLevel = texObj->BaseLevel; baseImage = _mesa_select_tex_image(texObj, target, srcLevel); if (!baseImage) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() couldn't find base teximage\n"); return true; } if (_mesa_is_format_compressed(baseImage->TexFormat)) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() with %s format\n", _mesa_get_format_name(baseImage->TexFormat)); return true; } if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB && !ctx->Extensions.EXT_texture_sRGB_decode) { /* The texture format is sRGB but we can't turn off sRGB->linear * texture sample conversion. So we won't be able to generate the * right colors when rendering. Need to use a fallback. */ _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() of sRGB texture without " "sRGB decode\n"); return true; } /* * Test that we can actually render in the texture's format. */ if (!mipmap->FBO) _mesa_GenFramebuffers(1, &mipmap->FBO); _mesa_BindFramebuffer(fbo_target, mipmap->FBO); _mesa_meta_bind_fbo_image(fbo_target, GL_COLOR_ATTACHMENT0, baseImage, 0); status = _mesa_CheckFramebufferStatus(fbo_target); _mesa_BindFramebuffer(fbo_target, fboSave); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() got incomplete FBO\n"); return true; } return false; }
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) { GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 }; 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; } /* 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; 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) return false; _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER | MESA_META_PIXEL_STORE)); /* 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); _mesa_GenFramebuffers(2, fbos); 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. */ if (tex_image) { _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_image, zoffset); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; } else { assert(depth == 1); } _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pbo_tex_image, 0); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; _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_bind_fbo_image(GL_READ_FRAMEBUFFER, 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_DeleteFramebuffers(2, fbos); _mesa_DeleteTextures(1, &pbo_tex); _mesa_DeleteBuffers(1, &pbo); _mesa_meta_end(ctx); return success; }
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 allocate_storage, bool create_pbo, const struct gl_pixelstore_attrib *packing) { GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 }; 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; 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) return false; if (allocate_storage) ctx->Driver.AllocTextureImageBuffer(ctx, tex_image); _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER | MESA_META_PIXEL_STORE)); _mesa_GenFramebuffers(2, fbos); _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); 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_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pbo_tex_image, 0); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_image, zoffset); /* If this passes on the first layer it should pass on the others */ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) goto fail; _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_bind_fbo_image(GL_DRAW_FRAMEBUFFER, 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_DeleteFramebuffers(2, fbos); _mesa_DeleteTextures(1, &pbo_tex); _mesa_DeleteBuffers(1, &pbo); _mesa_meta_end(ctx); return success; }