#include "main/arbprogram.h"
#include "main/arrayobj.h"
#include "main/blend.h"
+#include "main/blit.h"
#include "main/bufferobj.h"
#include "main/buffers.h"
+#include "main/clear.h"
#include "main/colortab.h"
#include "main/condrender.h"
#include "main/depth.h"
#include "main/fbobject.h"
#include "main/feedback.h"
#include "main/formats.h"
+#include "main/format_unpack.h"
#include "main/glformats.h"
#include "main/image.h"
#include "main/macros.h"
#include "main/mipmap.h"
#include "main/multisample.h"
#include "main/objectlabel.h"
+#include "main/pipelineobj.h"
#include "main/pixel.h"
#include "main/pbo.h"
#include "main/polygon.h"
#include "main/teximage.h"
#include "main/texparam.h"
#include "main/texstate.h"
+#include "main/texstore.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
#include "main/varray.h"
#include "drivers/common/meta.h"
#include "main/enums.h"
#include "main/glformats.h"
-#include "../glsl/ralloc.h"
+#include "util/ralloc.h"
/** Return offset in bytes of the field within a vertex struct */
#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl);
+
static struct blit_shader *
choose_blit_shader(GLenum target, struct blit_shader_table *table);
static void meta_decompress_cleanup(struct decompress_state *decompress);
static void meta_drawpix_cleanup(struct drawpix_state *drawpix);
+void
+_mesa_meta_bind_fbo_image(GLenum fboTarget, GLenum attachment,
+ struct gl_texture_image *texImage, GLuint layer)
+{
+ struct gl_texture_object *texObj = texImage->TexObject;
+ int level = texImage->Level;
+ GLenum texTarget = texObj->Target;
+
+ switch (texTarget) {
+ case GL_TEXTURE_1D:
+ _mesa_FramebufferTexture1D(fboTarget,
+ attachment,
+ texTarget,
+ texObj->Name,
+ level);
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_3D:
+ _mesa_FramebufferTextureLayer(fboTarget,
+ attachment,
+ texObj->Name,
+ level,
+ layer);
+ break;
+ default: /* 2D / cube */
+ if (texTarget == GL_TEXTURE_CUBE_MAP)
+ texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face;
+
+ _mesa_FramebufferTexture2D(fboTarget,
+ attachment,
+ texTarget,
+ texObj->Name,
+ level);
+ }
+}
+
GLuint
_mesa_meta_compile_shader_with_debug(struct gl_context *ctx, GLenum target,
const GLcharARB *source)
return 0;
}
+void
+_mesa_meta_compile_and_link_program(struct gl_context *ctx,
+ const char *vs_source,
+ const char *fs_source,
+ const char *name,
+ GLuint *program)
+{
+ GLuint vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER,
+ vs_source);
+ GLuint fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER,
+ fs_source);
+
+ *program = _mesa_CreateProgram();
+ _mesa_ObjectLabel(GL_PROGRAM, *program, -1, name);
+ _mesa_AttachShader(*program, fs);
+ _mesa_DeleteShader(fs);
+ _mesa_AttachShader(*program, vs);
+ _mesa_DeleteShader(vs);
+ _mesa_BindAttribLocation(*program, 0, "position");
+ _mesa_BindAttribLocation(*program, 1, "texcoords");
+ _mesa_meta_link_program_with_debug(ctx, *program);
+
+ _mesa_UseProgram(*program);
+}
+
/**
* Generate a generic shader to blit from a texture to a framebuffer
*
GLenum target,
struct blit_shader_table *table)
{
- const char *vs_source;
- char *fs_source;
- GLuint vs, fs;
+ char *vs_source, *fs_source;
void *const mem_ctx = ralloc_context(NULL);
struct blit_shader *shader = choose_blit_shader(target, table);
- char *name;
+ const char *vs_input, *vs_output, *fs_input, *vs_preprocess, *fs_preprocess;
+
+ if (ctx->Const.GLSLVersion < 130) {
+ vs_preprocess = "";
+ vs_input = "attribute";
+ vs_output = "varying";
+ fs_preprocess = "#extension GL_EXT_texture_array : enable";
+ fs_input = "varying";
+ } else {
+ vs_preprocess = "#version 130";
+ vs_input = "in";
+ vs_output = "out";
+ fs_preprocess = "#version 130";
+ fs_input = "in";
+ shader->func = "texture";
+ }
assert(shader != NULL);
return;
}
- if (ctx->Const.GLSLVersion < 130) {
- vs_source =
- "attribute vec2 position;\n"
- "attribute vec4 textureCoords;\n"
- "varying vec4 texCoords;\n"
- "void main()\n"
- "{\n"
- " texCoords = textureCoords;\n"
- " gl_Position = vec4(position, 0.0, 1.0);\n"
- "}\n";
-
- fs_source = ralloc_asprintf(mem_ctx,
- "#extension GL_EXT_texture_array : enable\n"
- "#extension GL_ARB_texture_cube_map_array: enable\n"
- "uniform %s texSampler;\n"
- "varying vec4 texCoords;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = %s(texSampler, %s);\n"
- " gl_FragDepth = gl_FragColor.x;\n"
- "}\n",
- shader->type,
- shader->func, shader->texcoords);
- }
- else {
- vs_source = ralloc_asprintf(mem_ctx,
- "#version 130\n"
- "in vec2 position;\n"
- "in vec4 textureCoords;\n"
- "out vec4 texCoords;\n"
- "void main()\n"
- "{\n"
- " texCoords = textureCoords;\n"
- " gl_Position = vec4(position, 0.0, 1.0);\n"
- "}\n");
- fs_source = ralloc_asprintf(mem_ctx,
- "#version 130\n"
- "#extension GL_ARB_texture_cube_map_array: enable\n"
- "uniform %s texSampler;\n"
- "in vec4 texCoords;\n"
- "out vec4 out_color;\n"
- "\n"
- "void main()\n"
- "{\n"
- " out_color = texture(texSampler, %s);\n"
- " gl_FragDepth = out_color.x;\n"
- "}\n",
- shader->type,
- shader->texcoords);
- }
-
- vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source);
- fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source);
-
- shader->shader_prog = _mesa_CreateProgram();
- _mesa_AttachShader(shader->shader_prog, fs);
- _mesa_DeleteShader(fs);
- _mesa_AttachShader(shader->shader_prog, vs);
- _mesa_DeleteShader(vs);
- _mesa_BindAttribLocation(shader->shader_prog, 0, "position");
- _mesa_BindAttribLocation(shader->shader_prog, 1, "texcoords");
- _mesa_meta_link_program_with_debug(ctx, shader->shader_prog);
- name = ralloc_asprintf(mem_ctx, "%s blit", shader->type);
- _mesa_ObjectLabel(GL_PROGRAM, shader->shader_prog, -1, name);
+ vs_source = ralloc_asprintf(mem_ctx,
+ "%s\n"
+ "%s vec2 position;\n"
+ "%s vec4 textureCoords;\n"
+ "%s vec4 texCoords;\n"
+ "void main()\n"
+ "{\n"
+ " texCoords = textureCoords;\n"
+ " gl_Position = vec4(position, 0.0, 1.0);\n"
+ "}\n",
+ vs_preprocess, vs_input, vs_input, vs_output);
+
+ fs_source = ralloc_asprintf(mem_ctx,
+ "%s\n"
+ "#extension GL_ARB_texture_cube_map_array: enable\n"
+ "uniform %s texSampler;\n"
+ "%s vec4 texCoords;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = %s(texSampler, %s);\n"
+ " gl_FragDepth = gl_FragColor.x;\n"
+ "}\n",
+ fs_preprocess, shader->type, fs_input,
+ shader->func, shader->texcoords);
+
+ _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source,
+ ralloc_asprintf(mem_ctx, "%s blit",
+ shader->type),
+ &shader->shader_prog);
ralloc_free(mem_ctx);
-
- _mesa_UseProgram(shader->shader_prog);
}
/**
ctx->Meta = CALLOC_STRUCT(gl_meta_state);
}
+static GLenum
+gl_buffer_index_to_drawbuffers_enum(gl_buffer_index bufindex)
+{
+ assert(bufindex < BUFFER_COUNT);
+
+ if (bufindex >= BUFFER_COLOR0)
+ return GL_COLOR_ATTACHMENT0 + bufindex - BUFFER_COLOR0;
+ else if (bufindex == BUFFER_FRONT_LEFT)
+ return GL_FRONT_LEFT;
+ else if (bufindex == BUFFER_FRONT_RIGHT)
+ return GL_FRONT_RIGHT;
+ else if (bufindex == BUFFER_BACK_LEFT)
+ return GL_BACK_LEFT;
+ else if (bufindex == BUFFER_BACK_RIGHT)
+ return GL_BACK_RIGHT;
+
+ return GL_NONE;
+}
/**
* Free context meta-op state.
_mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE);
}
+ if (state & MESA_META_DITHER) {
+ save->DitherFlag = ctx->Color.DitherFlag;
+ _mesa_set_enable(ctx, GL_DITHER, GL_TRUE);
+ }
+
if (state & MESA_META_COLOR_MASK) {
memcpy(save->ColorMask, ctx->Color.ColorMask,
sizeof(ctx->Color.ColorMask));
_mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, GL_FALSE);
}
- for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (ctx->Pipeline.Current) {
+ _mesa_reference_pipeline_object(ctx, &save->Pipeline,
+ ctx->Pipeline.Current);
+ _mesa_BindProgramPipeline(0);
+ }
+
+ /* Save the shader state from ctx->Shader (instead of ctx->_Shader) so
+ * that we don't have to worry about the current pipeline state.
+ */
+ for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
_mesa_reference_shader_program(ctx, &save->Shader[i],
- ctx->Shader.CurrentProgram[i]);
+ ctx->Shader.CurrentProgram[i]);
}
_mesa_reference_shader_program(ctx, &save->ActiveShader,
ctx->Shader.ActiveProgram);
_mesa_set_framebuffer_srgb(ctx, GL_FALSE);
}
+ if (state & MESA_META_DRAW_BUFFERS) {
+ int buf, real_color_buffers = 0;
+ memset(save->ColorDrawBuffers, 0, sizeof(save->ColorDrawBuffers));
+
+ for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
+ int buf_index = ctx->DrawBuffer->_ColorDrawBufferIndexes[buf];
+ if (buf_index == -1)
+ continue;
+
+ save->ColorDrawBuffers[buf] =
+ gl_buffer_index_to_drawbuffers_enum(buf_index);
+
+ if (++real_color_buffers >= ctx->DrawBuffer->_NumColorDrawBuffers)
+ break;
+ }
+ }
+
/* misc */
{
save->Lighting = ctx->Light.Enabled;
save->RasterDiscard = ctx->RasterDiscard;
if (ctx->RasterDiscard)
_mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE);
+
+ save->DrawBufferName = ctx->DrawBuffer->Name;
+ save->ReadBufferName = ctx->ReadBuffer->Name;
+ save->RenderbufferName = (ctx->CurrentRenderbuffer ?
+ ctx->CurrentRenderbuffer->Name : 0);
}
}
_mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled);
}
+ if (state & MESA_META_DITHER)
+ _mesa_set_enable(ctx, GL_DITHER, save->DitherFlag);
+
if (state & MESA_META_COLOR_MASK) {
GLuint i;
for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
}
if (state & MESA_META_SHADER) {
+ static const GLenum targets[] = {
+ GL_VERTEX_SHADER,
+ GL_GEOMETRY_SHADER,
+ GL_FRAGMENT_SHADER,
+ };
+
+ bool any_shader;
+
if (ctx->Extensions.ARB_vertex_program) {
_mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB,
save->VertexProgramEnabled);
save->ATIFragmentShaderEnabled);
}
- if (ctx->Extensions.ARB_vertex_shader) {
- _mesa_use_shader_program(ctx, GL_VERTEX_SHADER,
- save->Shader[MESA_SHADER_VERTEX]);
- }
+ any_shader = false;
+ for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
+ /* It is safe to call _mesa_use_shader_program even if the extension
+ * necessary for that program state is not supported. In that case,
+ * the saved program object must be NULL and the currently bound
+ * program object must be NULL. _mesa_use_shader_program is a no-op
+ * in that case.
+ */
+ _mesa_use_shader_program(ctx, targets[i],
+ save->Shader[i],
+ &ctx->Shader);
- if (_mesa_has_geometry_shaders(ctx))
- _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
- save->Shader[MESA_SHADER_GEOMETRY]);
+ /* Do this *before* killing the reference. :)
+ */
+ if (save->Shader[i] != NULL)
+ any_shader = true;
- if (ctx->Extensions.ARB_fragment_shader)
- _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER,
- save->Shader[MESA_SHADER_FRAGMENT]);
+ _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
+ }
_mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram,
- save->ActiveShader);
-
- for (i = 0; i < MESA_SHADER_STAGES; i++)
- _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
+ save->ActiveShader);
_mesa_reference_shader_program(ctx, &save->ActiveShader, NULL);
+
+ /* If there were any stages set with programs, use ctx->Shader as the
+ * current shader state. Otherwise, use Pipeline.Default. The pipeline
+ * hasn't been restored yet, and that may modify ctx->_Shader further.
+ */
+ if (any_shader)
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+ &ctx->Shader);
+ else
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+ ctx->Pipeline.Default);
+
+ if (save->Pipeline) {
+ _mesa_bind_pipeline(ctx, save->Pipeline);
+
+ _mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL);
+ }
}
if (state & MESA_META_STENCIL_TEST) {
if (save->TransformFeedbackNeedsResume)
_mesa_ResumeTransformFeedback();
+ if (ctx->DrawBuffer->Name != save->DrawBufferName)
+ _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, save->DrawBufferName);
+
+ if (ctx->ReadBuffer->Name != save->ReadBufferName)
+ _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, save->ReadBufferName);
+
+ if (!ctx->CurrentRenderbuffer ||
+ ctx->CurrentRenderbuffer->Name != save->RenderbufferName)
+ _mesa_BindRenderbuffer(GL_RENDERBUFFER, save->RenderbufferName);
+
+ if (state & MESA_META_DRAW_BUFFERS) {
+ _mesa_DrawBuffers(ctx->Const.MaxDrawBuffers, save->ColorDrawBuffers);
+ }
+
ctx->Meta->SaveStackDepth--;
ctx->API = save->API;
void
_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
{
- struct clear_state *clear = &ctx->Meta->Clear;
- struct vertex verts[4];
- /* save all state but scissor, pixel pack/unpack */
- GLbitfield metaSave = (MESA_META_ALL -
- MESA_META_SCISSOR -
- MESA_META_PIXEL_STORE -
- MESA_META_CONDITIONAL_RENDER -
- MESA_META_FRAMEBUFFER_SRGB);
- const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
-
- if (buffers & BUFFER_BITS_COLOR) {
- /* if clearing color buffers, don't save/restore colormask */
- metaSave -= MESA_META_COLOR_MASK;
- }
-
- _mesa_meta_begin(ctx, metaSave);
-
- _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
-
- /* GL_COLOR_BUFFER_BIT */
- if (buffers & BUFFER_BITS_COLOR) {
- /* leave colormask, glDrawBuffer state as-is */
-
- /* Clears never have the color clamped. */
- if (ctx->Extensions.ARB_color_buffer_float)
- _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
- }
- else {
- ASSERT(metaSave & MESA_META_COLOR_MASK);
- _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- }
-
- /* GL_DEPTH_BUFFER_BIT */
- if (buffers & BUFFER_BIT_DEPTH) {
- _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
- _mesa_DepthFunc(GL_ALWAYS);
- _mesa_DepthMask(GL_TRUE);
- }
- else {
- assert(!ctx->Depth.Test);
- }
-
- /* GL_STENCIL_BUFFER_BIT */
- if (buffers & BUFFER_BIT_STENCIL) {
- _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE);
- _mesa_StencilOpSeparate(GL_FRONT_AND_BACK,
- GL_REPLACE, GL_REPLACE, GL_REPLACE);
- _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS,
- ctx->Stencil.Clear & stencilMax,
- ctx->Stencil.WriteMask[0]);
- }
- else {
- assert(!ctx->Stencil.Enabled);
- }
-
- /* vertex positions/colors */
- {
- const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin;
- const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin;
- const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax;
- const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax;
- const GLfloat z = invert_z(ctx->Depth.Clear);
- GLuint i;
-
- verts[0].x = x0;
- verts[0].y = y0;
- verts[0].z = z;
- verts[1].x = x1;
- verts[1].y = y0;
- verts[1].z = z;
- verts[2].x = x1;
- verts[2].y = y1;
- verts[2].z = z;
- verts[3].x = x0;
- verts[3].y = y1;
- verts[3].z = z;
-
- /* vertex colors */
- for (i = 0; i < 4; i++) {
- verts[i].r = ctx->Color.ClearColor.f[0];
- verts[i].g = ctx->Color.ClearColor.f[1];
- verts[i].b = ctx->Color.ClearColor.f[2];
- verts[i].a = ctx->Color.ClearColor.f[3];
- }
-
- /* upload new vertex data */
- _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
- GL_DYNAMIC_DRAW_ARB);
- }
-
- /* draw quad */
- _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ meta_clear(ctx, buffers, false);
+}
- _mesa_meta_end(ctx);
+void
+_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+{
+ meta_clear(ctx, buffers, true);
}
static void
meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
{
const char *vs_source =
+ "#extension GL_AMD_vertex_shader_layer : enable\n"
+ "#extension GL_ARB_draw_instanced : enable\n"
"attribute vec4 position;\n"
"void main()\n"
"{\n"
+ "#ifdef GL_AMD_vertex_shader_layer\n"
+ " gl_Layer = gl_InstanceID;\n"
+ "#endif\n"
" gl_Position = position;\n"
"}\n";
- const char *gs_source =
- "#version 150\n"
- "layout(triangles) in;\n"
- "layout(triangle_strip, max_vertices = 4) out;\n"
- "uniform int layer;\n"
- "void main()\n"
- "{\n"
- " for (int i = 0; i < 3; i++) {\n"
- " gl_Layer = layer;\n"
- " gl_Position = gl_in[i].gl_Position;\n"
- " EmitVertex();\n"
- " }\n"
- "}\n";
const char *fs_source =
"uniform vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
- GLuint vs, gs = 0, fs;
+ GLuint vs, fs;
bool has_integer_textures;
_mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, true, 3, 0, 0);
_mesa_ShaderSource(vs, 1, &vs_source, NULL);
_mesa_CompileShader(vs);
- if (_mesa_has_geometry_shaders(ctx)) {
- gs = _mesa_CreateShader(GL_GEOMETRY_SHADER);
- _mesa_ShaderSource(gs, 1, &gs_source, NULL);
- _mesa_CompileShader(gs);
- }
-
fs = _mesa_CreateShader(GL_FRAGMENT_SHADER);
_mesa_ShaderSource(fs, 1, &fs_source, NULL);
_mesa_CompileShader(fs);
clear->ShaderProg = _mesa_CreateProgram();
_mesa_AttachShader(clear->ShaderProg, fs);
_mesa_DeleteShader(fs);
- if (gs != 0)
- _mesa_AttachShader(clear->ShaderProg, gs);
_mesa_AttachShader(clear->ShaderProg, vs);
_mesa_DeleteShader(vs);
_mesa_BindAttribLocation(clear->ShaderProg, 0, "position");
+ _mesa_ObjectLabel(GL_PROGRAM, clear->ShaderProg, -1, "meta clear");
_mesa_LinkProgram(clear->ShaderProg);
- clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg,
- "color");
- if (gs != 0) {
- clear->LayerLocation = _mesa_GetUniformLocation(clear->ShaderProg,
- "layer");
- }
+ clear->ColorLocation = _mesa_GetUniformLocation(clear->ShaderProg, "color");
has_integer_textures = _mesa_is_gles3(ctx) ||
(_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130);
const char *vs_int_source =
ralloc_asprintf(shader_source_mem_ctx,
"#version 130\n"
+ "#extension GL_AMD_vertex_shader_layer : enable\n"
+ "#extension GL_ARB_draw_instanced : enable\n"
"in vec4 position;\n"
"void main()\n"
"{\n"
+ "#ifdef GL_AMD_vertex_shader_layer\n"
+ " gl_Layer = gl_InstanceID;\n"
+ "#endif\n"
" gl_Position = position;\n"
"}\n");
const char *fs_int_source =
clear->IntegerShaderProg = _mesa_CreateProgram();
_mesa_AttachShader(clear->IntegerShaderProg, fs);
_mesa_DeleteShader(fs);
- if (gs != 0)
- _mesa_AttachShader(clear->IntegerShaderProg, gs);
_mesa_AttachShader(clear->IntegerShaderProg, vs);
_mesa_DeleteShader(vs);
_mesa_BindAttribLocation(clear->IntegerShaderProg, 0, "position");
clear->IntegerColorLocation =
_mesa_GetUniformLocation(clear->IntegerShaderProg, "color");
- if (gs != 0) {
- clear->IntegerLayerLocation =
- _mesa_GetUniformLocation(clear->IntegerShaderProg, "layer");
- }
}
- if (gs != 0)
- _mesa_DeleteShader(gs);
}
static void
}
/**
- * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ * Given a bitfield of BUFFER_BIT_x draw buffers, call glDrawBuffers to
+ * set GL to only draw to those buffers.
+ *
+ * Since the bitfield has no associated order, the assignment of draw buffer
+ * indices to color attachment indices is rather arbitrary.
*/
void
-_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+_mesa_meta_drawbuffers_from_bitfield(GLbitfield bits)
+{
+ GLenum enums[MAX_DRAW_BUFFERS];
+ int i = 0;
+ int n;
+
+ /* This function is only legal for color buffer bitfields. */
+ assert((bits & ~BUFFER_BITS_COLOR) == 0);
+
+ /* Make sure we don't overflow any arrays. */
+ assert(_mesa_bitcount(bits) <= MAX_DRAW_BUFFERS);
+
+ enums[0] = GL_NONE;
+
+ if (bits & BUFFER_BIT_FRONT_LEFT)
+ enums[i++] = GL_FRONT_LEFT;
+
+ if (bits & BUFFER_BIT_FRONT_RIGHT)
+ enums[i++] = GL_FRONT_RIGHT;
+
+ if (bits & BUFFER_BIT_BACK_LEFT)
+ enums[i++] = GL_BACK_LEFT;
+
+ if (bits & BUFFER_BIT_BACK_RIGHT)
+ enums[i++] = GL_BACK_RIGHT;
+
+ for (n = 0; n < MAX_COLOR_ATTACHMENTS; n++) {
+ if (bits & (1 << (BUFFER_COLOR0 + n)))
+ enums[i++] = GL_COLOR_ATTACHMENT0 + n;
+ }
+
+ _mesa_DrawBuffers(i, enums);
+}
+
+/**
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ */
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
{
struct clear_state *clear = &ctx->Meta->Clear;
GLbitfield metaSave;
const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
struct gl_framebuffer *fb = ctx->DrawBuffer;
- const float x0 = ((float)fb->_Xmin / fb->Width) * 2.0f - 1.0f;
- const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f;
- const float x1 = ((float)fb->_Xmax / fb->Width) * 2.0f - 1.0f;
- const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f;
- const float z = -invert_z(ctx->Depth.Clear);
+ float x0, y0, x1, y1, z;
struct vertex verts[4];
+ int i;
metaSave = (MESA_META_ALPHA_TEST |
MESA_META_BLEND |
MESA_META_MULTISAMPLE |
MESA_META_OCCLUSION_QUERY);
- if (!(buffers & BUFFER_BITS_COLOR)) {
+ if (!glsl) {
+ metaSave |= MESA_META_FOG |
+ MESA_META_PIXEL_TRANSFER |
+ MESA_META_TRANSFORM |
+ MESA_META_TEXTURE |
+ MESA_META_CLAMP_VERTEX_COLOR |
+ MESA_META_SELECT_FEEDBACK;
+ }
+
+ if (buffers & BUFFER_BITS_COLOR) {
+ metaSave |= MESA_META_DRAW_BUFFERS;
+ } else {
/* We'll use colormask to disable color writes. Otherwise,
* respect color mask
*/
_mesa_meta_begin(ctx, metaSave);
- meta_glsl_clear_init(ctx, clear);
+ if (glsl) {
+ meta_glsl_clear_init(ctx, clear);
+
+ x0 = ((float) fb->_Xmin / fb->Width) * 2.0f - 1.0f;
+ y0 = ((float) fb->_Ymin / fb->Height) * 2.0f - 1.0f;
+ x1 = ((float) fb->_Xmax / fb->Width) * 2.0f - 1.0f;
+ y1 = ((float) fb->_Ymax / fb->Height) * 2.0f - 1.0f;
+ z = -invert_z(ctx->Depth.Clear);
+ } else {
+ _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
+
+ x0 = (float) fb->_Xmin;
+ y0 = (float) fb->_Ymin;
+ x1 = (float) fb->_Xmax;
+ y1 = (float) fb->_Ymax;
+ z = invert_z(ctx->Depth.Clear);
+ }
if (fb->_IntegerColor) {
+ assert(glsl);
_mesa_UseProgram(clear->IntegerShaderProg);
_mesa_Uniform4iv(clear->IntegerColorLocation, 1,
ctx->Color.ClearColor.i);
- } else {
+ } else if (glsl) {
_mesa_UseProgram(clear->ShaderProg);
_mesa_Uniform4fv(clear->ColorLocation, 1,
ctx->Color.ClearColor.f);
/* GL_COLOR_BUFFER_BIT */
if (buffers & BUFFER_BITS_COLOR) {
- /* leave colormask, glDrawBuffer state as-is */
+ /* Only draw to the buffers we were asked to clear. */
+ _mesa_meta_drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
+
+ /* leave colormask state as-is */
/* Clears never have the color clamped. */
if (ctx->Extensions.ARB_color_buffer_float)
verts[3].y = y1;
verts[3].z = z;
+ if (!glsl) {
+ for (i = 0; i < 4; i++) {
+ verts[i].r = ctx->Color.ClearColor.f[0];
+ verts[i].g = ctx->Color.ClearColor.f[1];
+ verts[i].b = ctx->Color.ClearColor.f[2];
+ verts[i].a = ctx->Color.ClearColor.f[3];
+ }
+ }
+
/* upload new vertex data */
_mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
GL_DYNAMIC_DRAW_ARB);
/* draw quad(s) */
if (fb->MaxNumLayers > 0) {
- unsigned layer;
- for (layer = 0; layer < fb->MaxNumLayers; layer++) {
- if (fb->_IntegerColor)
- _mesa_Uniform1i(clear->IntegerLayerLocation, layer);
- else
- _mesa_Uniform1i(clear->LayerLocation, layer);
- _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
+ _mesa_DrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, fb->MaxNumLayers);
} else {
_mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
if (ctx->_ImageTransferState ||
ctx->FragmentProgram._Enabled ||
ctx->Fog.Enabled ||
- ctx->Texture._EnabledUnits ||
+ ctx->Texture._MaxEnabledTexImageUnit != -1 ||
width > tex->MaxSize ||
height > tex->MaxSize) {
_swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1);
GLuint i;
GLfloat r;
+ if (faceTarget == GL_TEXTURE_CUBE_MAP_ARRAY)
+ faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice % 6;
+
/* Currently all texture targets want the W component to be 1.0.
*/
coords0[3] = 1.0F;
coord = coords3;
break;
default:
- assert(0);
+ unreachable("not reached");
}
coord[3] = (float) (slice / 6);
static GLenum
get_temp_image_type(struct gl_context *ctx, mesa_format format)
{
- GLenum baseFormat;
-
- baseFormat = _mesa_get_format_base_format(format);
+ const GLenum baseFormat = _mesa_get_format_base_format(format);
+ const GLenum datatype = _mesa_get_format_datatype(format);
+ const GLint format_red_bits = _mesa_get_format_bits(format, GL_RED_BITS);
switch (baseFormat) {
case GL_RGBA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
case GL_INTENSITY:
- if (ctx->DrawBuffer->Visual.redBits <= 8) {
+ if (datatype == GL_INT || datatype == GL_UNSIGNED_INT) {
+ return datatype;
+ } else if (format_red_bits <= 8) {
return GL_UNSIGNED_BYTE;
- } else if (ctx->DrawBuffer->Visual.redBits <= 16) {
+ } else if (format_red_bits <= 16) {
return GL_UNSIGNED_SHORT;
- } else {
- GLenum datatype = _mesa_get_format_datatype(format);
- if (datatype == GL_INT || datatype == GL_UNSIGNED_INT)
- return datatype;
- return GL_FLOAT;
}
- case GL_DEPTH_COMPONENT: {
- GLenum datatype = _mesa_get_format_datatype(format);
+ return GL_FLOAT;
+ case GL_DEPTH_COMPONENT:
if (datatype == GL_FLOAT)
return GL_FLOAT;
else
return GL_UNSIGNED_INT;
- }
- case GL_DEPTH_STENCIL: {
- GLenum datatype = _mesa_get_format_datatype(format);
+ case GL_DEPTH_STENCIL:
if (datatype == GL_FLOAT)
return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
else
return GL_UNSIGNED_INT_24_8;
- }
default:
_mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()",
baseFormat);
}
}
+/**
+ * Attempts to wrap the destination texture in an FBO and use
+ * glBlitFramebuffer() to implement glCopyTexSubImage().
+ */
+static bool
+copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
+ struct gl_texture_image *texImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ struct gl_renderbuffer *rb,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ struct gl_texture_object *texObj = texImage->TexObject;
+ GLuint fbo;
+ bool success = false;
+ GLbitfield mask;
+ GLenum status;
+
+ if (!ctx->Extensions.ARB_framebuffer_object)
+ return false;
+
+ _mesa_unlock_texture(ctx, texObj);
+
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
+
+ _mesa_GenFramebuffers(1, &fbo);
+ _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+
+ if (rb->_BaseFormat == GL_DEPTH_STENCIL ||
+ rb->_BaseFormat == GL_DEPTH_COMPONENT) {
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ texImage, zoffset);
+ mask = GL_DEPTH_BUFFER_BIT;
+
+ if (rb->_BaseFormat == GL_DEPTH_STENCIL &&
+ texImage->_BaseFormat == GL_DEPTH_STENCIL) {
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ texImage, zoffset);
+ mask |= GL_STENCIL_BUFFER_BIT;
+ }
+ _mesa_DrawBuffer(GL_NONE);
+ } else {
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texImage, zoffset);
+ mask = GL_COLOR_BUFFER_BIT;
+ _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
+ }
+
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ goto out;
+
+ ctx->Meta->Blit.no_ctsi_fallback = true;
+
+ /* 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, which
+ * are too strict for CopyTexImage. We know meta will be fine with format
+ * changes.
+ */
+ mask = _mesa_meta_BlitFramebuffer(ctx, x, y,
+ x + width, y + height,
+ xoffset, yoffset,
+ xoffset + width, yoffset + height,
+ mask, GL_NEAREST);
+ ctx->Meta->Blit.no_ctsi_fallback = false;
+ success = mask == 0x0;
+
+ out:
+ _mesa_lock_texture(ctx, texObj);
+ _mesa_DeleteFramebuffers(1, &fbo);
+ _mesa_meta_end(ctx);
+ return success;
+}
/**
* Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions.
GLint bpp;
void *buf;
- /* The gl_renderbuffer is part of the interface for
- * dd_function_table::CopyTexSubImage, but this implementation does not use
- * it.
- */
- (void) rb;
+ if (copytexsubimage_using_blit_framebuffer(ctx, dims,
+ texImage,
+ xoffset, yoffset, zoffset,
+ rb,
+ x, y,
+ width, height)) {
+ return;
+ }
/* Choose format/type for temporary image buffer */
format = _mesa_get_format_base_format(texImage->TexFormat);
free(buf);
}
+static void
+meta_decompress_fbo_cleanup(struct decompress_fbo_state *decompress_fbo)
+{
+ if (decompress_fbo->FBO != 0) {
+ _mesa_DeleteFramebuffers(1, &decompress_fbo->FBO);
+ _mesa_DeleteRenderbuffers(1, &decompress_fbo->RBO);
+ }
+
+ memset(decompress_fbo, 0, sizeof(*decompress_fbo));
+}
static void
meta_decompress_cleanup(struct decompress_state *decompress)
{
- if (decompress->FBO != 0) {
- _mesa_DeleteFramebuffers(1, &decompress->FBO);
- _mesa_DeleteRenderbuffers(1, &decompress->RBO);
- }
+ meta_decompress_fbo_cleanup(&decompress->byteFBO);
+ meta_decompress_fbo_cleanup(&decompress->floatFBO);
if (decompress->VAO != 0) {
_mesa_DeleteVertexArrays(1, &decompress->VAO);
* \param dest destination buffer
* \param destRowLength dest image rowLength (ala GL_PACK_ROW_LENGTH)
*/
-static void
+static bool
decompress_texture_image(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice,
GLvoid *dest)
{
struct decompress_state *decompress = &ctx->Meta->Decompress;
+ struct decompress_fbo_state *decompress_fbo;
struct gl_texture_object *texObj = texImage->TexObject;
const GLint width = texImage->Width;
const GLint height = texImage->Height;
const GLint depth = texImage->Height;
const GLenum target = texObj->Target;
+ GLenum rbFormat;
GLenum faceTarget;
struct vertex verts[4];
- GLuint fboDrawSave, fboReadSave;
- GLuint rbSave;
GLuint samplerSave;
+ GLenum status;
const bool use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
ctx->Extensions.ARB_fragment_shader;
+ switch (_mesa_get_format_datatype(texImage->TexFormat)) {
+ case GL_FLOAT:
+ decompress_fbo = &decompress->floatFBO;
+ rbFormat = GL_RGBA32F;
+ break;
+ case GL_UNSIGNED_NORMALIZED:
+ decompress_fbo = &decompress->byteFBO;
+ rbFormat = GL_RGBA;
+ break;
+ default:
+ return false;
+ }
+
if (slice > 0) {
assert(target == GL_TEXTURE_3D ||
target == GL_TEXTURE_2D_ARRAY ||
case GL_TEXTURE_1D:
case GL_TEXTURE_1D_ARRAY:
assert(!"No compressed 1D textures.");
- return;
+ return false;
case GL_TEXTURE_3D:
assert(!"No compressed 3D textures.");
- return;
+ return false;
case GL_TEXTURE_CUBE_MAP_ARRAY:
faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (slice % 6);
break;
}
- /* save fbo bindings (not saved by _mesa_meta_begin()) */
- fboDrawSave = ctx->DrawBuffer->Name;
- fboReadSave = ctx->ReadBuffer->Name;
- rbSave = ctx->CurrentRenderbuffer ? ctx->CurrentRenderbuffer->Name : 0;
-
- _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_PIXEL_STORE);
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~(MESA_META_PIXEL_STORE |
+ MESA_META_DRAW_BUFFERS));
samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
/* Create/bind FBO/renderbuffer */
- if (decompress->FBO == 0) {
- _mesa_GenFramebuffers(1, &decompress->FBO);
- _mesa_GenRenderbuffers(1, &decompress->RBO);
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
- _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
+ if (decompress_fbo->FBO == 0) {
+ _mesa_GenFramebuffers(1, &decompress_fbo->FBO);
+ _mesa_GenRenderbuffers(1, &decompress_fbo->RBO);
+ _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
+ _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
_mesa_FramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT,
- decompress->RBO);
+ decompress_fbo->RBO);
}
else {
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress->FBO);
+ _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, decompress_fbo->FBO);
}
/* alloc dest surface */
- if (width > decompress->Width || height > decompress->Height) {
- _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress->RBO);
- _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, GL_RGBA,
- width, height);
- decompress->Width = width;
- decompress->Height = height;
+ if (width > decompress_fbo->Width || height > decompress_fbo->Height) {
+ _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, decompress_fbo->RBO);
+ _mesa_RenderbufferStorage(GL_RENDERBUFFER_EXT, rbFormat,
+ width, height);
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ /* If the framebuffer isn't complete then we'll leave
+ * decompress_fbo->Width as zero so that it will fail again next time
+ * too */
+ _mesa_meta_end(ctx);
+ return false;
+ }
+ decompress_fbo->Width = width;
+ decompress_fbo->Height = height;
}
if (use_glsl_version) {
_mesa_meta_end(ctx);
- /* restore fbo bindings */
- if (fboDrawSave == fboReadSave) {
- _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboDrawSave);
- }
- else {
- _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave);
- _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, fboReadSave);
- }
- _mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, rbSave);
+ return true;
}
GLenum format, GLenum type, GLvoid *pixels,
struct gl_texture_image *texImage)
{
- /* We can only use the decompress-with-blit method here if the texels are
- * unsigned, normalized values. We could handle signed and unnormalized
- * with floating point renderbuffers...
- */
- if (_mesa_is_format_compressed(texImage->TexFormat) &&
- _mesa_get_format_datatype(texImage->TexFormat)
- == GL_UNSIGNED_NORMALIZED) {
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
struct gl_texture_object *texObj = texImage->TexObject;
GLuint slice;
+ bool result;
+
/* Need to unlock the texture here to prevent deadlock... */
_mesa_unlock_texture(ctx, texObj);
for (slice = 0; slice < texImage->Depth; slice++) {
else {
dst = pixels;
}
- decompress_texture_image(ctx, texImage, slice, format, type, dst);
+ result = decompress_texture_image(ctx, texImage, slice,
+ format, type, dst);
+ if (!result)
+ break;
}
/* ... and relock it */
_mesa_lock_texture(ctx, texObj);
+
+ if (result)
+ return;
}
- else {
- _mesa_get_teximage(ctx, format, type, pixels, texImage);
- }
+
+ _mesa_get_teximage(ctx, format, type, pixels, texImage);
}
GLfloat s, t, s1, t1;
GLuint tw, th;
- if (!ctx->Texture.Unit[i]._ReallyEnabled) {
+ if (!ctx->Texture.Unit[i]._Current) {
GLuint j;
for (j = 0; j < 4; j++) {
verts[j].st[i][0] = 0.0f;
_mesa_meta_end(ctx);
}
+
+static bool
+cleartexsubimage_color(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ const GLvoid *clearValue,
+ GLint zoffset)
+{
+ mesa_format format;
+ union gl_color_union colorValue;
+ GLenum datatype;
+ GLenum status;
+
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texImage, zoffset);
+
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ return false;
+
+ /* We don't want to apply an sRGB conversion so override the format */
+ format = _mesa_get_srgb_format_linear(texImage->TexFormat);
+ datatype = _mesa_get_format_datatype(format);
+
+ switch (datatype) {
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ if (clearValue)
+ _mesa_unpack_uint_rgba_row(format, 1, clearValue,
+ (GLuint (*)[4]) colorValue.ui);
+ else
+ memset(&colorValue, 0, sizeof colorValue);
+ if (datatype == GL_INT)
+ _mesa_ClearBufferiv(GL_COLOR, 0, colorValue.i);
+ else
+ _mesa_ClearBufferuiv(GL_COLOR, 0, colorValue.ui);
+ break;
+ default:
+ if (clearValue)
+ _mesa_unpack_rgba_row(format, 1, clearValue,
+ (GLfloat (*)[4]) colorValue.f);
+ else
+ memset(&colorValue, 0, sizeof colorValue);
+ _mesa_ClearBufferfv(GL_COLOR, 0, colorValue.f);
+ break;
+ }
+
+ return true;
+}
+
+static bool
+cleartexsubimage_depth_stencil(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ const GLvoid *clearValue,
+ GLint zoffset)
+{
+ GLint stencilValue;
+ GLfloat depthValue;
+ GLenum status;
+
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ texImage, zoffset);
+
+ if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+ _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ texImage, zoffset);
+
+ status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ return false;
+
+ if (clearValue) {
+ GLuint depthStencilValue[2];
+
+ /* Convert the clearValue from whatever format it's in to a floating
+ * point value for the depth and an integer value for the stencil index
+ */
+ _mesa_unpack_float_32_uint_24_8_depth_stencil_row(texImage->TexFormat,
+ 1, /* n */
+ clearValue,
+ depthStencilValue);
+ /* We need a memcpy here instead of a cast because we need to
+ * reinterpret the bytes as a float rather than converting it
+ */
+ memcpy(&depthValue, depthStencilValue, sizeof depthValue);
+ stencilValue = depthStencilValue[1] & 0xff;
+ } else {
+ depthValue = 0.0f;
+ stencilValue = 0;
+ }
+
+ if (texImage->_BaseFormat == GL_DEPTH_STENCIL)
+ _mesa_ClearBufferfi(GL_DEPTH_STENCIL, 0, depthValue, stencilValue);
+ else
+ _mesa_ClearBufferfv(GL_DEPTH, 0, &depthValue);
+
+ return true;
+}
+
+static bool
+cleartexsubimage_for_zoffset(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint zoffset,
+ const GLvoid *clearValue)
+{
+ GLuint fbo;
+ bool success;
+
+ _mesa_GenFramebuffers(1, &fbo);
+ _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+
+ switch(texImage->_BaseFormat) {
+ case GL_DEPTH_STENCIL:
+ case GL_DEPTH_COMPONENT:
+ success = cleartexsubimage_depth_stencil(ctx, texImage,
+ clearValue, zoffset);
+ break;
+ default:
+ success = cleartexsubimage_color(ctx, texImage, clearValue, zoffset);
+ break;
+ }
+
+ _mesa_DeleteFramebuffers(1, &fbo);
+
+ return success;
+}
+
+static bool
+cleartexsubimage_using_fbo(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const GLvoid *clearValue)
+{
+ bool success = true;
+ GLint z;
+
+ _mesa_meta_begin(ctx,
+ MESA_META_SCISSOR |
+ MESA_META_COLOR_MASK |
+ MESA_META_DITHER |
+ MESA_META_FRAMEBUFFER_SRGB);
+
+ _mesa_set_enable(ctx, GL_DITHER, GL_FALSE);
+
+ _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE);
+ _mesa_Scissor(xoffset, yoffset, width, height);
+
+ for (z = zoffset; z < zoffset + depth; z++) {
+ if (!cleartexsubimage_for_zoffset(ctx, texImage, z, clearValue)) {
+ success = false;
+ break;
+ }
+ }
+
+ _mesa_meta_end(ctx);
+
+ return success;
+}
+
+extern void
+_mesa_meta_ClearTexSubImage(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ const GLvoid *clearValue)
+{
+ bool res;
+
+ _mesa_unlock_texture(ctx, texImage->TexObject);
+
+ res = cleartexsubimage_using_fbo(ctx, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ clearValue);
+
+ _mesa_lock_texture(ctx, texImage->TexObject);
+
+ if (res)
+ return;
+
+ _mesa_warning(ctx,
+ "Falling back to mapping the texture in "
+ "glClearTexSubImage\n");
+
+ _mesa_store_cleartexsubimage(ctx, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ clearValue);
+}