aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/drivers/common
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/drivers/common')
-rw-r--r--mesalib/src/mesa/drivers/common/meta.c370
-rw-r--r--mesalib/src/mesa/drivers/common/meta.h18
-rw-r--r--mesalib/src/mesa/drivers/common/meta_generate_mipmap.c383
3 files changed, 414 insertions, 357 deletions
diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c
index cde34f99f..030e1116e 100644
--- a/mesalib/src/mesa/drivers/common/meta.c
+++ b/mesalib/src/mesa/drivers/common/meta.c
@@ -89,7 +89,6 @@ choose_blit_shader(GLenum target, struct blit_shader_table *table);
static void cleanup_temp_texture(struct temp_texture *tex);
static void meta_glsl_clear_cleanup(struct clear_state *clear);
-static void meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap);
static void meta_decompress_cleanup(struct decompress_state *decompress);
static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
@@ -361,7 +360,7 @@ _mesa_meta_free(struct gl_context *ctx)
_mesa_make_current(ctx, NULL, NULL);
_mesa_meta_glsl_blit_cleanup(&ctx->Meta->Blit);
meta_glsl_clear_cleanup(&ctx->Meta->Clear);
- meta_glsl_generate_mipmap_cleanup(&ctx->Meta->Mipmap);
+ _mesa_meta_glsl_generate_mipmap_cleanup(&ctx->Meta->Mipmap);
cleanup_temp_texture(&ctx->Meta->TempTex);
meta_decompress_cleanup(&ctx->Meta->Decompress);
meta_drawpix_cleanup(&ctx->Meta->DrawPix);
@@ -2360,102 +2359,6 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
_mesa_meta_end(ctx);
}
-
-/**
- * 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
- */
-GLboolean
-_mesa_meta_check_generate_mipmap_fallback(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) {
- _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
- "glGenerateMipmap() to %s target\n",
- _mesa_lookup_enum_by_nr(target));
- return GL_TRUE;
- }
-
- srcLevel = texObj->BaseLevel;
- baseImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel);
- if (!baseImage) {
- _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
- "glGenerateMipmap() couldn't find base teximage\n");
- return GL_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;
- }
-
- 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 GL_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);
- }
-
- 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 GL_TRUE;
- }
-
- return GL_FALSE;
-}
-
-
/**
* Compute the texture coordinates for the four vertices of a quad for
* drawing a 2D texture image or slice of a cube/3D texture.
@@ -2465,16 +2368,16 @@ _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target,
* \param height height of the texture image
* \param coords0/1/2/3 returns the computed texcoords
*/
-static void
-setup_texture_coords(GLenum faceTarget,
- GLint slice,
- GLint width,
- GLint height,
- GLint depth,
- GLfloat coords0[4],
- GLfloat coords1[4],
- GLfloat coords2[4],
- GLfloat coords3[4])
+void
+_mesa_meta_setup_texture_coords(GLenum faceTarget,
+ GLint slice,
+ GLint width,
+ GLint height,
+ GLint depth,
+ GLfloat coords0[4],
+ GLfloat coords1[4],
+ GLfloat coords2[4],
+ GLfloat coords3[4])
{
static const GLfloat st[4][2] = {
{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
@@ -2618,7 +2521,7 @@ setup_texture_coords(GLenum faceTarget,
}
break;
default:
- assert(0 && "unexpected target in meta setup_texture_coords()");
+ assert(!"unexpected target in _mesa_meta_setup_texture_coords()");
}
}
@@ -2698,245 +2601,6 @@ _mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table)
table->sampler_cubemap_array.shader_prog = 0;
}
-static void
-meta_glsl_generate_mipmap_cleanup(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_meta_blit_shader_table_cleanup(&mipmap->shaders);
-}
-
-
-/**
- * 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 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;
-
- if (_mesa_meta_check_generate_mipmap_fallback(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);
-
- /* 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);
- }
- 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->FBO) {
- _mesa_GenFramebuffers(1, &mipmap->FBO);
- }
-
- 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);
- }
-
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
-
- _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);
-
- /* Silence valgrind warnings about reading uninitialized stack. */
- memset(verts, 0, sizeof(verts));
-
- /* Setup texture coordinates */
- 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;
- 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;
-
- /* 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);
-
- for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) {
- const struct gl_texture_image *srcImage;
- const GLuint srcLevel = dstLevel - 1;
- GLsizei srcWidth, srcHeight, srcDepth;
- GLsizei dstWidth, dstHeight, dstDepth;
- GLenum status;
-
- srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel);
- assert(srcImage->Border == 0);
-
- /* src size */
- srcWidth = srcImage->Width;
- srcHeight = srcImage->Height;
- srcDepth = srcImage->Depth;
-
- /* new dst size */
- dstWidth = MAX2(1, srcWidth / 2);
- dstHeight = MAX2(1, srcHeight / 2);
- dstDepth = MAX2(1, srcDepth / 2);
-
- if (dstWidth == srcImage->Width &&
- dstHeight == srcImage->Height &&
- dstDepth == srcImage->Depth) {
- /* 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 (!_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_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
-
- /* sanity check */
- status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- _mesa_problem(ctx, "Unexpected incomplete framebuffer in "
- "_mesa_meta_GenerateMipmap()");
- break;
- }
-
- assert(dstWidth == ctx->DrawBuffer->Width);
- assert(dstHeight == ctx->DrawBuffer->Height);
-
- /* setup viewport */
- _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight);
-
- _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);
-
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);
-}
-
-
/**
* Determine the GL data type to use for the temporary image read with
* ReadPixels() and passed to Tex[Sub]Image().
@@ -3219,11 +2883,11 @@ decompress_texture_image(struct gl_context *ctx,
/* Silence valgrind warnings about reading uninitialized stack. */
memset(verts, 0, sizeof(verts));
- setup_texture_coords(faceTarget, slice, width, height, depth,
- verts[0].tex,
- verts[1].tex,
- verts[2].tex,
- verts[3].tex);
+ _mesa_meta_setup_texture_coords(faceTarget, slice, width, height, depth,
+ verts[0].tex,
+ verts[1].tex,
+ verts[2].tex,
+ verts[3].tex);
/* setup vertex positions */
verts[0].x = -1.0F;
diff --git a/mesalib/src/mesa/drivers/common/meta.h b/mesalib/src/mesa/drivers/common/meta.h
index fcf45c403..6029a775c 100644
--- a/mesalib/src/mesa/drivers/common/meta.h
+++ b/mesalib/src/mesa/drivers/common/meta.h
@@ -410,10 +410,6 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap);
-extern GLboolean
-_mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target,
- struct gl_texture_object *texObj);
-
extern void
_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
struct gl_texture_object *texObj);
@@ -448,6 +444,17 @@ GLboolean
_mesa_meta_alloc_texture(struct temp_texture *tex,
GLsizei width, GLsizei height, GLenum intFormat);
+void
+_mesa_meta_setup_texture_coords(GLenum faceTarget,
+ GLint slice,
+ GLint width,
+ GLint height,
+ GLint depth,
+ GLfloat coords0[4],
+ GLfloat coords1[4],
+ GLfloat coords2[4],
+ GLfloat coords3[4]);
+
struct temp_texture *
_mesa_meta_get_temp_texture(struct gl_context *ctx);
@@ -491,4 +498,7 @@ _mesa_meta_glsl_blit_cleanup(struct blit_state *blit);
void
_mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table);
+void
+_mesa_meta_glsl_generate_mipmap_cleanup(struct gen_mipmap_state *mipmap);
+
#endif /* META_H */
diff --git a/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c b/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c
new file mode 100644
index 000000000..3db073ab1
--- /dev/null
+++ b/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c
@@ -0,0 +1,383 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Meta operations. Some GL operations can be expressed in terms of
+ * other GL operations. For example, glBlitFramebuffer() can be done
+ * with texture mapping and glClear() can be done with polygon rendering.
+ *
+ * \author Brian Paul
+ */
+
+#include "main/arrayobj.h"
+#include "main/buffers.h"
+#include "main/enums.h"
+#include "main/enable.h"
+#include "main/fbobject.h"
+#include "main/macros.h"
+#include "main/mipmap.h"
+#include "main/teximage.h"
+#include "main/texobj.h"
+#include "main/texparam.h"
+#include "main/varray.h"
+#include "main/viewport.h"
+#include "drivers/common/meta.h"
+
+/**
+ * Bind a particular texture level/layer to mipmap->FBO's GL_COLOR_ATTACHMENT0.
+ */
+static void
+bind_fbo_image(struct gl_texture_object *texObj, GLenum target,
+ GLuint level, GLuint layer)
+{
+ switch (target) {
+ case GL_TEXTURE_1D:
+ _mesa_FramebufferTexture1D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ target,
+ texObj->Name,
+ level);
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_3D:
+ _mesa_FramebufferTextureLayer(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ texObj->Name,
+ level,
+ layer);
+ break;
+ default: /* 2D / cube */
+ _mesa_FramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ target,
+ texObj->Name,
+ level);
+ }
+}
+
+/**
+ * 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(ctx, 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);
+
+ bind_fbo_image(texObj, target, srcLevel, 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;
+}
+
+void
+_mesa_meta_glsl_generate_mipmap_cleanup(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_meta_blit_shader_table_cleanup(&mipmap->shaders);
+}
+
+static GLboolean
+prepare_mipmap_level(struct gl_context *ctx,
+ struct gl_texture_object *texObj, GLuint level,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum intFormat, mesa_format format)
+{
+ if (texObj->Target == GL_TEXTURE_1D_ARRAY) {
+ /* Work around Mesa expecting the number of array slices in "height". */
+ height = depth;
+ depth = 1;
+ }
+
+ return _mesa_prepare_mipmap_level(ctx, texObj, level, width, height, depth,
+ 0, intFormat, format);
+}
+
+/**
+ * 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 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;
+ GLuint samplerSave;
+
+ 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);
+
+ /* 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);
+ } 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);
+
+ /* 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;
+ const GLuint srcLevel = dstLevel - 1;
+ GLuint layer;
+ GLsizei srcWidth, srcHeight, srcDepth;
+ GLsizei dstWidth, dstHeight, dstDepth;
+
+ srcImage = _mesa_select_tex_image(ctx, 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;
+ }
+
+ /* 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);
+
+ bind_fbo_image(texObj, faceTarget, dstLevel, 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);
+
+ _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);
+}