X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fcommon%2Fmeta.c;h=485128696c5ae476f2ca7f4ce7a2c610210c5520;hb=89b1f5d6ac669343b1ee00f288e2ee71eb15dbe2;hp=d3910597dea7c6e7f911a24275e43abdac144f40;hpb=ca21cffebd063354291d561eadc2ded8795a5333;p=mesa.git diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index d3910597dea..485128696c5 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -40,6 +40,7 @@ #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" @@ -47,6 +48,7 @@ #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" @@ -71,6 +73,7 @@ #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" @@ -81,11 +84,14 @@ #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); @@ -95,18 +101,18 @@ 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 attachment, +_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 target = texObj->Target; + GLenum texTarget = texObj->Target; - switch (target) { + switch (texTarget) { case GL_TEXTURE_1D: - _mesa_FramebufferTexture1D(GL_FRAMEBUFFER, + _mesa_FramebufferTexture1D(fboTarget, attachment, - target, + texTarget, texObj->Name, level); break; @@ -115,19 +121,19 @@ _mesa_meta_bind_fbo_image(GLenum attachment, case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_3D: - _mesa_FramebufferTextureLayer(GL_FRAMEBUFFER, + _mesa_FramebufferTextureLayer(fboTarget, attachment, texObj->Name, level, layer); break; default: /* 2D / cube */ - if (target == GL_TEXTURE_CUBE_MAP) - target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; + if (texTarget == GL_TEXTURE_CUBE_MAP) + texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; - _mesa_FramebufferTexture2D(GL_FRAMEBUFFER, + _mesa_FramebufferTexture2D(fboTarget, attachment, - target, + texTarget, texObj->Name, level); } @@ -201,6 +207,31 @@ _mesa_meta_link_program_with_debug(struct gl_context *ctx, GLuint program) 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 * @@ -214,12 +245,25 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx, 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); @@ -228,73 +272,36 @@ _mesa_meta_setup_blit_shader(struct gl_context *ctx, 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); } /** @@ -389,6 +396,24 @@ _mesa_meta_init(struct gl_context *ctx) 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. @@ -483,6 +508,11 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield 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)); @@ -576,11 +606,10 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, GL_FALSE); } - if (ctx->Extensions.ARB_separate_shader_objects) { - if (ctx->Pipeline.Current) { - _mesa_reference_pipeline_object(ctx, &save->Pipeline, - ctx->Pipeline.Current); - _mesa_BindProgramPipeline(0); + 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 @@ -776,6 +805,23 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) _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; @@ -837,6 +883,9 @@ _mesa_meta_end(struct gl_context *ctx) _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++) { @@ -975,7 +1024,6 @@ _mesa_meta_end(struct gl_context *ctx) ctx->Pipeline.Default); if (save->Pipeline) { - assert(ctx->Extensions.ARB_separate_shader_objects); _mesa_bind_pipeline(ctx, save->Pipeline); _mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL); @@ -1175,6 +1223,10 @@ _mesa_meta_end(struct gl_context *ctx) 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; @@ -1461,131 +1513,36 @@ _mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO, 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); @@ -1597,12 +1554,6 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) _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); @@ -1610,19 +1561,13 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) 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); @@ -1632,9 +1577,14 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) 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 = @@ -1657,8 +1607,6 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) 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"); @@ -1674,13 +1622,7 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) 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 @@ -1702,21 +1644,60 @@ meta_glsl_clear_cleanup(struct clear_state *clear) } /** - * 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 | @@ -1731,7 +1712,18 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) 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 */ @@ -1740,13 +1732,30 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) _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); @@ -1754,7 +1763,10 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) /* 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) @@ -1802,20 +1814,22 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) 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); } @@ -2578,7 +2592,7 @@ _mesa_meta_setup_texture_coords(GLenum faceTarget, coord = coords3; break; default: - assert(0); + unreachable("not reached"); } coord[3] = (float) (slice / 6); @@ -2707,9 +2721,9 @@ _mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table) 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: @@ -2720,30 +2734,24 @@ get_temp_image_type(struct gl_context *ctx, mesa_format format) 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); @@ -2776,24 +2784,27 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims, _mesa_unlock_texture(ctx, texObj); - _mesa_meta_begin(ctx, MESA_META_ALL); + _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_DEPTH_ATTACHMENT, texImage, zoffset); + _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_STENCIL_ATTACHMENT, texImage, zoffset); + _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_COLOR_ATTACHMENT0, texImage, zoffset); + _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + texImage, zoffset); mask = GL_COLOR_BUFFER_BIT; _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0); } @@ -2814,13 +2825,13 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims, * are too strict for CopyTexImage. We know meta will be fine with format * changes. */ - _mesa_meta_BlitFramebuffer(ctx, x, y, - x + width, y + height, - xoffset, yoffset, - xoffset + width, yoffset + height, - mask, GL_NEAREST); + 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 = true; + success = mask == 0x0; out: _mesa_lock_texture(ctx, texObj); @@ -2921,14 +2932,22 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims, 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); @@ -2950,7 +2969,7 @@ meta_decompress_cleanup(struct decompress_state *decompress) * \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, @@ -2958,17 +2977,33 @@ decompress_texture_image(struct gl_context *ctx, 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 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 || @@ -2979,11 +3014,11 @@ decompress_texture_image(struct gl_context *ctx, 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); @@ -2998,33 +3033,42 @@ decompress_texture_image(struct gl_context *ctx, break; } - _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) { @@ -3146,6 +3190,8 @@ decompress_texture_image(struct gl_context *ctx, _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); _mesa_meta_end(ctx); + + return true; } @@ -3159,15 +3205,11 @@ _mesa_meta_GetTexImage(struct gl_context *ctx, 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++) { @@ -3189,14 +3231,19 @@ _mesa_meta_GetTexImage(struct gl_context *ctx, 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); } @@ -3324,3 +3371,192 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, _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); +}