#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"
#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
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));
+ _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");
/*
* 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) {
+ GLuint FBO;
- status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
+ _mesa_CreateFramebuffers(1, &FBO);
+ mipmap->fb = _mesa_lookup_framebuffer(ctx, FBO);
+ assert(mipmap->fb != NULL && mipmap->fb->Name == FBO);
+ }
- _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");
}
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);
+
+ if (mipmap->fb != NULL) {
+ _mesa_DeleteFramebuffers(1, &mipmap->fb->Name);
+ mipmap->fb = NULL;
+ }
_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.
+ * Note: We don't yet support 3D textures, or texture borders.
*/
void
_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 (fallback_required(ctx, target, texObj)) {
_mesa_generate_mipmap(ctx, target, texObj);
faceTarget = target;
}
- _mesa_meta_begin(ctx, MESA_META_ALL);
+ _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, 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;
-
- if (currentTexUnitSave != 0)
- _mesa_BindTexture(target, texObj->Name);
+ _mesa_reference_sampler_object(ctx, &samp_obj_save,
+ ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler);
- if (!mipmap->Sampler) {
- _mesa_GenSamplers(1, &mipmap->Sampler);
- _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->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_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);
+ _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.
- * 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);
+ /* 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);
}
- assert(mipmap->FBO != 0);
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);
+ _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, mipmap->samp_obj);
+
+ assert(mipmap->fb != NULL);
+ _mesa_bind_framebuffers(ctx, mipmap->fb, mipmap->fb);
- _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);
+ _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;
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;
+ 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;
}
/* 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);
+ _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
+ (GLint *) &dstLevel, false);
- if (!_mesa_prepare_mipmap_level(ctx, texObj, dstLevel,
- dstWidth, dstHeight, dstDepth,
- srcImage->Border,
- srcImage->InternalFormat,
- srcImage->TexFormat)) {
+ 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);
-
- /* 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);
+ _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);
}