X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fcommon%2Fmeta_generate_mipmap.c;h=bbe9d6d8863116712c4741431f0c3aa758fbe6f8;hb=c06480390b68c7118b0628f0a2702e6a8c67e1e0;hp=f1bc291fc584c19a7660dd40a15176d9228f7fab;hpb=70e7905608b374f65d1f4b657f8ab61808c76ef6;p=mesa.git diff --git a/src/mesa/drivers/common/meta_generate_mipmap.c b/src/mesa/drivers/common/meta_generate_mipmap.c index f1bc291fc58..bbe9d6d8863 100644 --- a/src/mesa/drivers/common/meta_generate_mipmap.c +++ b/src/mesa/drivers/common/meta_generate_mipmap.c @@ -31,10 +31,12 @@ */ #include "main/arrayobj.h" +#include "main/blend.h" #include "main/buffers.h" #include "main/enums.h" #include "main/enable.h" #include "main/fbobject.h" +#include "main/framebuffer.h" #include "main/macros.h" #include "main/mipmap.h" #include "main/teximage.h" @@ -43,6 +45,8 @@ #include "main/varray.h" #include "main/viewport.h" #include "drivers/common/meta.h" +#include "program/prog_instruction.h" + /** * Check if the call to _mesa_meta_GenerateMipmap() will require a @@ -50,39 +54,36 @@ * images are mapped. * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise */ -GLboolean -_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) +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 || - target == GL_TEXTURE_1D_ARRAY || - target == GL_TEXTURE_2D_ARRAY) { + 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 GL_TRUE; + _mesa_enum_to_string(target)); + return true; } srcLevel = texObj->BaseLevel; - baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel); + 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 GL_TRUE; + 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 GL_TRUE; + return true; } if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB && @@ -94,67 +95,53 @@ _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() of sRGB texture without " "sRGB decode\n"); - return GL_TRUE; + 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); - - if (target == GL_TEXTURE_1D) { - _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel); - } -#if 0 - /* other work is needed to enable 3D mipmap generation */ - else if (target == GL_TEXTURE_3D) { - GLint zoffset = 0; - _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel, zoffset); - } -#endif - else { - /* 2D / cube */ - _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, texObj->Name, srcLevel); + if (mipmap->fb == NULL) { + mipmap->fb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF); + if (mipmap->fb == NULL) { + _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, + "glGenerateMipmap() ran out of memory\n"); + return true; + } } - status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); - - _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave); + _mesa_meta_framebuffer_texture_image(ctx, mipmap->fb, + GL_COLOR_ATTACHMENT0, baseImage, 0); + status = _mesa_check_framebuffer_status(ctx, mipmap->fb); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH, "glGenerateMipmap() got incomplete FBO\n"); - return GL_TRUE; + return true; } - return GL_FALSE; + return false; } void -_mesa_meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap) +_mesa_meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, + struct gen_mipmap_state *mipmap) { if (mipmap->VAO == 0) return; _mesa_DeleteVertexArrays(1, &mipmap->VAO); mipmap->VAO = 0; - _mesa_DeleteBuffers(1, &mipmap->VBO); - mipmap->VBO = 0; + _mesa_reference_buffer_object(ctx, &mipmap->buf_obj, NULL); + _mesa_reference_sampler_object(ctx, &mipmap->samp_obj, NULL); + _mesa_reference_framebuffer(&mipmap->fb, NULL); - _mesa_meta_blit_shader_table_cleanup(&mipmap->shaders); + _mesa_meta_blit_shader_table_cleanup(ctx, &mipmap->shaders); } + /** * Called via ctx->Driver.GenerateMipmap() - * Note: We don't yet support 3D textures, 1D/2D array textures or texture - * borders. + * Note: We don't yet support 3D textures, or texture borders. */ void _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, @@ -166,16 +153,21 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, const GLuint maxLevel = texObj->MaxLevel; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; - const GLuint fboSave = ctx->DrawBuffer->Name; - 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; - const GLint slice = 0; - GLuint samplerSave; + 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 (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) { + if (fallback_required(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); return; } @@ -188,70 +180,78 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, faceTarget = target; } - _mesa_meta_begin(ctx, MESA_META_ALL); + _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(&mipmap->VAO, &mipmap->VBO, true, - 2, 3, 0); - _mesa_meta_setup_blit_shader(ctx, target, &mipmap->shaders); + _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(&mipmap->VAO, &mipmap->VBO, 3); + _mesa_meta_setup_ff_tnl_for_blit(ctx, &mipmap->VAO, &mipmap->buf_obj, 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; + _mesa_reference_sampler_object(ctx, &samp_obj_save, + ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler); - if (currentTexUnitSave != 0) - _mesa_BindTexture(target, texObj->Name); + /* 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; + } - if (!mipmap->FBO) { - _mesa_GenFramebuffers(1, &mipmap->FBO); + _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); } - 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); + if (ctx->Extensions.EXT_texture_sRGB_decode) { + const struct gl_texture_image *baseImage = + _mesa_select_tex_image(texObj, target, texObj->BaseLevel); + const bool srgb = + _mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB; + + _mesa_set_sampler_srgb_decode(ctx, mipmap->samp_obj, + srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT); + _mesa_set_framebuffer_srgb(ctx, srgb); } - _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO); + _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, mipmap->samp_obj); - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); + 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 texture coordinates */ - _mesa_meta_setup_texture_coords(faceTarget, - slice, - 0, 0, 1, /* width, height never used here */ - verts[0].tex, - verts[1].tex, - verts[2].tex, - verts[3].tex); - /* setup vertex positions */ verts[0].x = -1.0F; verts[0].y = -1.0F; @@ -262,36 +262,40 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, verts[3].x = -1.0F; verts[3].y = 1.0F; - /* upload vertex data */ - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - verts, GL_DYNAMIC_DRAW_ARB); - /* 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; - GLenum status; - srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel); + srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel); assert(srcImage->Border == 0); /* src size */ srcWidth = srcImage->Width; - srcHeight = srcImage->Height; - srcDepth = srcImage->Depth; + if (target == GL_TEXTURE_1D_ARRAY) { + srcHeight = 1; + srcDepth = srcImage->Height; + } else { + srcHeight = srcImage->Height; + srcDepth = srcImage->Depth; + } /* new dst size */ - dstWidth = MAX2(1, srcWidth / 2); - dstHeight = MAX2(1, srcHeight / 2); - dstDepth = MAX2(1, srcDepth / 2); + dstWidth = minify(srcWidth, 1); + dstHeight = minify(srcHeight, 1); + dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth; - if (dstWidth == srcImage->Width && - dstHeight == srcImage->Height && - dstDepth == srcImage->Depth) { + if (dstWidth == srcWidth && + dstHeight == srcHeight && + dstDepth == srcDepth) { /* all done */ break; } @@ -299,74 +303,77 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, /* 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 (!_mesa_prepare_mipmap_level(ctx, texObj, dstLevel, - dstWidth, dstHeight, dstDepth, - srcImage->Border, - 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; - } - - /* limit minification to src level */ - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); - - /* Set to draw into the current dstLevel */ - if (target == GL_TEXTURE_1D) { - _mesa_FramebufferTexture1D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, - texObj->Name, - dstLevel); - } - else if (target == GL_TEXTURE_3D) { - GLint zoffset = 0; /* XXX unfinished */ - _mesa_FramebufferTexture3D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - target, - texObj->Name, - dstLevel, zoffset); - } else { - /* 2D / cube */ - _mesa_FramebufferTexture2D(GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT0_EXT, - faceTarget, - texObj->Name, - dstLevel); - } + _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, + (GLint *) &dstLevel, false); - _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); - /* sanity check */ - status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_problem(ctx, "Unexpected incomplete framebuffer in " - "_mesa_meta_GenerateMipmap()"); + /* 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; - } - assert(dstWidth == ctx->DrawBuffer->Width); - assert(dstHeight == ctx->DrawBuffer->Height); + /* 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_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + _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_BindSampler(ctx->Texture.CurrentUnit, samplerSave); + _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj_save); + _mesa_reference_sampler_object(ctx, &samp_obj_save, NULL); _mesa_meta_end(ctx); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); + _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, &maxLevelSave, + false); if (genMipmapSave) - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); - - _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave); + _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_true, + false); + if (swizzleSaved) + _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzle, + false); }