X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fcommon%2Fmeta.c;h=485128696c5ae476f2ca7f4ce7a2c610210c5520;hb=89b1f5d6ac669343b1ee00f288e2ee71eb15dbe2;hp=6185e807c611e1486c34c29fb64a1ad49e676860;hpb=fcb498302bff912ca4f3169d37cc04b58e77d0fa;p=mesa.git diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 6185e807c61..485128696c5 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -37,8 +37,10 @@ #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" @@ -46,11 +48,15 @@ #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/matrix.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" @@ -67,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" @@ -77,295 +84,70 @@ #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)) -/** - * State which we may save/restore across meta ops. - * XXX this may be incomplete... - */ -struct save_state -{ - GLbitfield SavedState; /**< bitmask of MESA_META_* flags */ - - /** MESA_META_CLEAR (and others?) */ - struct gl_query_object *CurrentOcclusionObject; - - /** MESA_META_ALPHA_TEST */ - GLboolean AlphaEnabled; - GLenum AlphaFunc; - GLclampf AlphaRef; - - /** MESA_META_BLEND */ - GLbitfield BlendEnabled; - GLboolean ColorLogicOpEnabled; - - /** MESA_META_COLOR_MASK */ - GLubyte ColorMask[MAX_DRAW_BUFFERS][4]; - - /** MESA_META_DEPTH_TEST */ - struct gl_depthbuffer_attrib Depth; - - /** MESA_META_FOG */ - GLboolean Fog; - - /** MESA_META_PIXEL_STORE */ - struct gl_pixelstore_attrib Pack, Unpack; - - /** MESA_META_PIXEL_TRANSFER */ - GLfloat RedBias, RedScale; - GLfloat GreenBias, GreenScale; - GLfloat BlueBias, BlueScale; - GLfloat AlphaBias, AlphaScale; - GLfloat DepthBias, DepthScale; - GLboolean MapColorFlag; - - /** MESA_META_RASTERIZATION */ - GLenum FrontPolygonMode, BackPolygonMode; - GLboolean PolygonOffset; - GLboolean PolygonSmooth; - GLboolean PolygonStipple; - GLboolean PolygonCull; - - /** MESA_META_SCISSOR */ - struct gl_scissor_attrib Scissor; - - /** MESA_META_SHADER */ - GLboolean VertexProgramEnabled; - struct gl_vertex_program *VertexProgram; - GLboolean FragmentProgramEnabled; - struct gl_fragment_program *FragmentProgram; - GLboolean ATIFragmentShaderEnabled; - struct gl_shader_program *Shader[MESA_SHADER_STAGES]; - struct gl_shader_program *ActiveShader; - - /** MESA_META_STENCIL_TEST */ - struct gl_stencil_attrib Stencil; - - /** MESA_META_TRANSFORM */ - GLenum MatrixMode; - GLfloat ModelviewMatrix[16]; - GLfloat ProjectionMatrix[16]; - GLfloat TextureMatrix[16]; - - /** MESA_META_CLIP */ - GLbitfield ClipPlanesEnabled; - - /** MESA_META_TEXTURE */ - GLuint ActiveUnit; - GLuint ClientActiveUnit; - /** for unit[0] only */ - struct gl_texture_object *CurrentTexture[NUM_TEXTURE_TARGETS]; - /** mask of TEXTURE_2D_BIT, etc */ - GLbitfield TexEnabled[MAX_TEXTURE_UNITS]; - GLbitfield TexGenEnabled[MAX_TEXTURE_UNITS]; - GLuint EnvMode; /* unit[0] only */ - - /** MESA_META_VERTEX */ - struct gl_array_object *ArrayObj; - struct gl_buffer_object *ArrayBufferObj; - - /** MESA_META_VIEWPORT */ - GLfloat ViewportX, ViewportY, ViewportW, ViewportH; - GLclampd DepthNear, DepthFar; - - /** MESA_META_CLAMP_FRAGMENT_COLOR */ - GLenum ClampFragmentColor; - - /** MESA_META_CLAMP_VERTEX_COLOR */ - GLenum ClampVertexColor; - - /** MESA_META_CONDITIONAL_RENDER */ - struct gl_query_object *CondRenderQuery; - GLenum CondRenderMode; - - /** MESA_META_SELECT_FEEDBACK */ - GLenum RenderMode; - struct gl_selection Select; - struct gl_feedback Feedback; - - /** MESA_META_MULTISAMPLE */ - GLboolean MultisampleEnabled; - - /** MESA_META_FRAMEBUFFER_SRGB */ - GLboolean sRGBEnabled; - - /** Miscellaneous (always disabled) */ - GLboolean Lighting; - GLboolean RasterDiscard; - GLboolean TransformFeedbackNeedsResume; -}; - -/** - * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. - * This is currently shared by all the meta ops. But we could create a - * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. - */ -struct temp_texture -{ - GLuint TexObj; - GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ - GLsizei MinSize; /**< Min texture size to allocate */ - GLsizei MaxSize; /**< Max possible texture size */ - GLboolean NPOT; /**< Non-power of two size OK? */ - GLsizei Width, Height; /**< Current texture size */ - GLenum IntFormat; - GLfloat Sright, Ttop; /**< right, top texcoords */ -}; - - -/** - * State for glBlitFramebufer() - */ -struct blit_state -{ - GLuint ArrayObj; - GLuint VBO; - GLuint DepthFP; - GLuint ShaderProg; - GLuint RectShaderProg; - struct temp_texture depthTex; -}; - - -/** - * State for glClear() - */ -struct clear_state -{ - GLuint ArrayObj; - GLuint VBO; - GLuint ShaderProg; - GLint ColorLocation; - GLint LayerLocation; - - GLuint IntegerShaderProg; - GLint IntegerColorLocation; - GLint IntegerLayerLocation; -}; - - -/** - * State for glCopyPixels() - */ -struct copypix_state -{ - GLuint ArrayObj; - GLuint VBO; -}; - - -/** - * State for glDrawPixels() - */ -struct drawpix_state -{ - GLuint ArrayObj; - - GLuint StencilFP; /**< Fragment program for drawing stencil images */ - GLuint DepthFP; /**< Fragment program for drawing depth images */ -}; - - -/** - * State for glBitmap() - */ -struct bitmap_state -{ - GLuint ArrayObj; - GLuint VBO; - struct temp_texture Tex; /**< separate texture from other meta ops */ -}; +static void +meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl); -/** - * State for GLSL texture sampler which is used to generate fragment - * shader in _mesa_meta_generate_mipmap(). - */ -struct glsl_sampler { - const char *type; - const char *func; - const char *texcoords; - GLuint shader_prog; -}; +static struct blit_shader * +choose_blit_shader(GLenum target, struct blit_shader_table *table); -/** - * State for _mesa_meta_generate_mipmap() - */ -struct gen_mipmap_state -{ - GLuint ArrayObj; - GLuint VBO; - GLuint FBO; - GLuint Sampler; - GLuint ShaderProg; - struct glsl_sampler sampler_1d; - struct glsl_sampler sampler_2d; - struct glsl_sampler sampler_3d; - struct glsl_sampler sampler_cubemap; - struct glsl_sampler sampler_1d_array; - struct glsl_sampler sampler_2d_array; -}; +static void cleanup_temp_texture(struct temp_texture *tex); +static void meta_glsl_clear_cleanup(struct clear_state *clear); +static void meta_decompress_cleanup(struct decompress_state *decompress); +static void meta_drawpix_cleanup(struct drawpix_state *drawpix); -/** - * State for texture decompression - */ -struct decompress_state +void +_mesa_meta_bind_fbo_image(GLenum fboTarget, GLenum attachment, + struct gl_texture_image *texImage, GLuint layer) { - GLuint ArrayObj; - GLuint VBO, FBO, RBO, Sampler; - GLint Width, Height; -}; + struct gl_texture_object *texObj = texImage->TexObject; + int level = texImage->Level; + GLenum texTarget = texObj->Target; -/** - * State for glDrawTex() - */ -struct drawtex_state -{ - GLuint ArrayObj; - GLuint VBO; -}; + 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; -#define MAX_META_OPS_DEPTH 8 -/** - * All per-context meta state. - */ -struct gl_meta_state -{ - /** Stack of state saved during meta-ops */ - struct save_state Save[MAX_META_OPS_DEPTH]; - /** Save stack depth */ - GLuint SaveStackDepth; - - struct temp_texture TempTex; - - struct blit_state Blit; /**< For _mesa_meta_BlitFramebuffer() */ - struct clear_state Clear; /**< For _mesa_meta_Clear() */ - struct copypix_state CopyPix; /**< For _mesa_meta_CopyPixels() */ - struct drawpix_state DrawPix; /**< For _mesa_meta_DrawPixels() */ - struct bitmap_state Bitmap; /**< For _mesa_meta_Bitmap() */ - struct gen_mipmap_state Mipmap; /**< For _mesa_meta_GenerateMipmap() */ - struct decompress_state Decompress; /**< For texture decompression */ - struct drawtex_state DrawTex; /**< For _mesa_meta_DrawTex() */ -}; - -static void meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit); -static void cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex); -static void meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear); -static void meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, - struct gen_mipmap_state *mipmap); -static void meta_decompress_cleanup(struct decompress_state *decompress); -static void meta_drawpix_cleanup(struct drawpix_state *drawpix); + _mesa_FramebufferTexture2D(fboTarget, + attachment, + texTarget, + texObj->Name, + level); + } +} -static GLuint -compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB *source) +GLuint +_mesa_meta_compile_shader_with_debug(struct gl_context *ctx, GLenum target, + const GLcharARB *source) { GLuint shader; GLint ok, size; GLchar *info; - shader = _mesa_CreateShaderObjectARB(target); + shader = _mesa_CreateShader(target); _mesa_ShaderSource(shader, 1, &source, NULL); _mesa_CompileShader(shader); @@ -375,30 +157,30 @@ compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB _mesa_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); if (size == 0) { - _mesa_DeleteObjectARB(shader); + _mesa_DeleteShader(shader); return 0; } info = malloc(size); if (!info) { - _mesa_DeleteObjectARB(shader); + _mesa_DeleteShader(shader); return 0; } - _mesa_GetProgramInfoLog(shader, size, NULL, info); + _mesa_GetShaderInfoLog(shader, size, NULL, info); _mesa_problem(ctx, "meta program compile failed:\n%s\n" "source:\n%s\n", info, source); free(info); - _mesa_DeleteObjectARB(shader); + _mesa_DeleteShader(shader); return 0; } -static GLuint -link_program_with_debug(struct gl_context *ctx, GLuint program) +GLuint +_mesa_meta_link_program_with_debug(struct gl_context *ctx, GLuint program) { GLint ok, size; GLchar *info; @@ -425,6 +207,183 @@ 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 + * + * \param ctx Current GL context + * \param texTarget Texture target that will be the source of the blit + * + * \returns a handle to a shader program on success or zero on failure. + */ +void +_mesa_meta_setup_blit_shader(struct gl_context *ctx, + GLenum target, + struct blit_shader_table *table) +{ + char *vs_source, *fs_source; + void *const mem_ctx = ralloc_context(NULL); + struct blit_shader *shader = choose_blit_shader(target, table); + 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); + + if (shader->shader_prog != 0) { + _mesa_UseProgram(shader->shader_prog); + return; + } + + 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); +} + +/** + * Configure vertex buffer and vertex array objects for tests + * + * Regardless of whether a new VAO and new VBO are created, the objects + * referenced by \c VAO and \c VBO will be bound into the GL state vector + * when this function terminates. + * + * \param VAO Storage for vertex array object handle. If 0, a new VAO + * will be created. + * \param VBO Storage for vertex buffer object handle. If 0, a new VBO + * will be created. The new VBO will have storage for 4 + * \c vertex structures. + * \param use_generic_attributes Should generic attributes 0 and 1 be used, + * or should traditional, fixed-function color and texture + * coordinate be used? + * \param vertex_size Number of components for attribute 0 / vertex. + * \param texcoord_size Number of components for attribute 1 / texture + * coordinate. If this is 0, attribute 1 will not be set or + * enabled. + * \param color_size Number of components for attribute 1 / primary color. + * If this is 0, attribute 1 will not be set or enabled. + * + * \note If \c use_generic_attributes is \c true, \c color_size must be zero. + * Use \c texcoord_size instead. + */ +void +_mesa_meta_setup_vertex_objects(GLuint *VAO, GLuint *VBO, + bool use_generic_attributes, + unsigned vertex_size, unsigned texcoord_size, + unsigned color_size) +{ + if (*VAO == 0) { + assert(*VBO == 0); + + /* create vertex array object */ + _mesa_GenVertexArrays(1, VAO); + _mesa_BindVertexArray(*VAO); + + /* create vertex array buffer */ + _mesa_GenBuffers(1, VBO); + _mesa_BindBuffer(GL_ARRAY_BUFFER, *VBO); + _mesa_BufferData(GL_ARRAY_BUFFER, 4 * sizeof(struct vertex), NULL, + GL_DYNAMIC_DRAW); + + /* setup vertex arrays */ + if (use_generic_attributes) { + assert(color_size == 0); + + _mesa_VertexAttribPointer(0, vertex_size, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), OFFSET(x)); + _mesa_EnableVertexAttribArray(0); + + if (texcoord_size > 0) { + _mesa_VertexAttribPointer(1, texcoord_size, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), OFFSET(tex)); + _mesa_EnableVertexAttribArray(1); + } + } else { + _mesa_VertexPointer(vertex_size, GL_FLOAT, sizeof(struct vertex), + OFFSET(x)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + + if (texcoord_size > 0) { + _mesa_TexCoordPointer(texcoord_size, GL_FLOAT, + sizeof(struct vertex), OFFSET(tex)); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (color_size > 0) { + _mesa_ColorPointer(color_size, GL_FLOAT, + sizeof(struct vertex), OFFSET(r)); + _mesa_EnableClientState(GL_COLOR_ARRAY); + } + } + } else { + _mesa_BindVertexArray(*VAO); + _mesa_BindBuffer(GL_ARRAY_BUFFER, *VBO); + } +} + /** * Initialize meta-ops for a context. * To be called once during context creation. @@ -437,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. @@ -447,10 +424,10 @@ _mesa_meta_free(struct gl_context *ctx) { GET_CURRENT_CONTEXT(old_context); _mesa_make_current(ctx, NULL, NULL); - meta_glsl_blit_cleanup(ctx, &ctx->Meta->Blit); - meta_glsl_clear_cleanup(ctx, &ctx->Meta->Clear); - meta_glsl_generate_mipmap_cleanup(ctx, &ctx->Meta->Mipmap); - cleanup_temp_texture(ctx, &ctx->Meta->TempTex); + _mesa_meta_glsl_blit_cleanup(&ctx->Meta->Blit); + meta_glsl_clear_cleanup(&ctx->Meta->Clear); + _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); if (old_context) @@ -481,6 +458,13 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) memset(save, 0, sizeof(*save)); save->SavedState = state; + /* We always push into desktop GL mode and pop out at the end. No sense in + * writing our shaders varying based on the user's context choice, when + * Mesa can handle either. + */ + save->API = ctx->API; + ctx->API = API_OPENGL_COMPAT; + /* Pausing transform feedback needs to be done early, or else we won't be * able to change other state. */ @@ -524,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)); @@ -540,9 +529,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); } - if ((state & MESA_META_FOG) - && ctx->API != API_OPENGL_CORE - && ctx->API != API_OPENGLES2) { + if (state & MESA_META_FOG) { save->Fog = ctx->Fog.Enabled; if (ctx->Fog.Enabled) _mesa_set_enable(ctx, GL_FOG, GL_FALSE); @@ -587,10 +574,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) save->PolygonCull = ctx->Polygon.CullFlag; _mesa_PolygonMode(GL_FRONT_AND_BACK, GL_FILL); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, GL_FALSE); - if (ctx->API == API_OPENGL_COMPAT) { - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); - } + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE); } @@ -602,28 +587,37 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) if (state & MESA_META_SHADER) { int i; - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) { + if (ctx->Extensions.ARB_vertex_program) { save->VertexProgramEnabled = ctx->VertexProgram.Enabled; _mesa_reference_vertprog(ctx, &save->VertexProgram, ctx->VertexProgram.Current); _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE); } - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) { + if (ctx->Extensions.ARB_fragment_program) { save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled; _mesa_reference_fragprog(ctx, &save->FragmentProgram, ctx->FragmentProgram.Current); _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE); } - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) { + if (ctx->Extensions.ATI_fragment_shader) { save->ATIFragmentShaderEnabled = ctx->ATIFragmentShader.Enabled; _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); @@ -646,33 +640,24 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) save->EnvMode = ctx->Texture.Unit[0].EnvMode; /* Disable all texture units */ - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; - save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled; - if (ctx->Texture.Unit[u].Enabled || - ctx->Texture.Unit[u].TexGenEnabled) { - _mesa_ActiveTexture(GL_TEXTURE0 + u); - _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); - if (ctx->Extensions.ARB_texture_cube_map) - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); - if (_mesa_is_gles(ctx) && - ctx->Extensions.OES_EGL_image_external) - _mesa_set_enable(ctx, GL_TEXTURE_EXTERNAL_OES, GL_FALSE); - - if (ctx->API == API_OPENGL_COMPAT) { - _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); - if (ctx->Extensions.NV_texture_rectangle) - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); - } else { - _mesa_set_enable(ctx, GL_TEXTURE_GEN_STR_OES, GL_FALSE); - } - } + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; + save->TexGenEnabled[u] = ctx->Texture.Unit[u].TexGenEnabled; + if (ctx->Texture.Unit[u].Enabled || + ctx->Texture.Unit[u].TexGenEnabled) { + _mesa_ActiveTexture(GL_TEXTURE0 + u); + _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); + if (ctx->Extensions.ARB_texture_cube_map) + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); + + _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); + if (ctx->Extensions.NV_texture_rectangle) + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); } } @@ -685,9 +670,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) /* set defaults for unit[0] */ _mesa_ActiveTexture(GL_TEXTURE0); _mesa_ClientActiveTexture(GL_TEXTURE0); - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - } + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } if (state & MESA_META_TRANSFORM) { @@ -730,8 +713,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) if (state & MESA_META_VERTEX) { /* save vertex array object state */ - _mesa_reference_array_object(ctx, &save->ArrayObj, - ctx->Array.ArrayObj); + _mesa_reference_vao(ctx, &save->VAO, + ctx->Array.VAO); _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, ctx->Array.ArrayBufferObj); /* set some default state? */ @@ -800,9 +783,20 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) } if (state & MESA_META_MULTISAMPLE) { - save->MultisampleEnabled = ctx->Multisample.Enabled; + save->Multisample = ctx->Multisample; /* struct copy */ + if (ctx->Multisample.Enabled) _mesa_set_multisample(ctx, GL_FALSE); + if (ctx->Multisample.SampleCoverage) + _mesa_set_enable(ctx, GL_SAMPLE_COVERAGE, GL_FALSE); + if (ctx->Multisample.SampleAlphaToCoverage) + _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_COVERAGE, GL_FALSE); + if (ctx->Multisample.SampleAlphaToOne) + _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_ONE, GL_FALSE); + if (ctx->Multisample.SampleShading) + _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_FALSE); + if (ctx->Multisample.SampleMask) + _mesa_set_enable(ctx, GL_SAMPLE_MASK, GL_FALSE); } if (state & MESA_META_FRAMEBUFFER_SRGB) { @@ -811,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; @@ -819,6 +830,11 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) 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); } } @@ -867,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++) { @@ -893,9 +912,7 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_DepthMask(save->Depth.Mask); } - if ((state & MESA_META_FOG) - && ctx->API != API_OPENGL_CORE - && ctx->API != API_OPENGLES2) { + if (state & MESA_META_FOG) { _mesa_set_enable(ctx, GL_FOG, save->Fog); } @@ -919,18 +936,10 @@ _mesa_meta_end(struct gl_context *ctx) } if (state & MESA_META_RASTERIZATION) { - /* Core context requires that front and back mode be the same. - */ - if (ctx->API == API_OPENGL_CORE) { - _mesa_PolygonMode(GL_FRONT_AND_BACK, save->FrontPolygonMode); - } else { - _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); - _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); - } - if (ctx->API == API_OPENGL_COMPAT) { - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); - } + _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); + _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); + _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); + _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth); _mesa_set_enable(ctx, GL_POLYGON_OFFSET_FILL, save->PolygonOffset); _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); } @@ -950,7 +959,15 @@ _mesa_meta_end(struct gl_context *ctx) } if (state & MESA_META_SHADER) { - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_vertex_program) { + 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); _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, @@ -958,7 +975,7 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL); } - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ARB_fragment_program) { + if (ctx->Extensions.ARB_fragment_program) { _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, save->FragmentProgramEnabled); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, @@ -966,30 +983,51 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_reference_fragprog(ctx, &save->FragmentProgram, NULL); } - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_fragment_shader) { + if (ctx->Extensions.ATI_fragment_shader) { _mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, 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) { @@ -997,7 +1035,7 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); - if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.EXT_stencil_two_side) { + if (ctx->Extensions.EXT_stencil_two_side) { _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, stencil->TestTwoSide); _mesa_ActiveStencilFaceEXT(stencil->ActiveFace @@ -1029,9 +1067,7 @@ _mesa_meta_end(struct gl_context *ctx) ASSERT(ctx->Texture.CurrentUnit == 0); /* restore texenv for unit[0] */ - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); - } + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); /* restore texture objects for unit[0] only */ for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { @@ -1044,17 +1080,15 @@ _mesa_meta_end(struct gl_context *ctx) } /* Restore fixed function texture enables, texgen */ - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - if (ctx->Texture.Unit[u].Enabled != save->TexEnabled[u]) { - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.Unit[u].Enabled = save->TexEnabled[u]; - } + for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { + if (ctx->Texture.Unit[u].Enabled != save->TexEnabled[u]) { + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + ctx->Texture.Unit[u].Enabled = save->TexEnabled[u]; + } - if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) { - FLUSH_VERTICES(ctx, _NEW_TEXTURE); - ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u]; - } + if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) { + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u]; } } @@ -1096,8 +1130,8 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj, NULL); /* restore vertex array object */ - _mesa_BindVertexArray(save->ArrayObj->Name); - _mesa_reference_array_object(ctx, &save->ArrayObj, NULL); + _mesa_BindVertexArray(save->VAO->Name); + _mesa_reference_vao(ctx, &save->VAO, NULL); } if (state & MESA_META_VIEWPORT) { @@ -1138,8 +1172,30 @@ _mesa_meta_end(struct gl_context *ctx) } if (state & MESA_META_MULTISAMPLE) { - if (ctx->Multisample.Enabled != save->MultisampleEnabled) - _mesa_set_multisample(ctx, save->MultisampleEnabled); + struct gl_multisample_attrib *ctx_ms = &ctx->Multisample; + struct gl_multisample_attrib *save_ms = &save->Multisample; + + if (ctx_ms->Enabled != save_ms->Enabled) + _mesa_set_multisample(ctx, save_ms->Enabled); + if (ctx_ms->SampleCoverage != save_ms->SampleCoverage) + _mesa_set_enable(ctx, GL_SAMPLE_COVERAGE, save_ms->SampleCoverage); + if (ctx_ms->SampleAlphaToCoverage != save_ms->SampleAlphaToCoverage) + _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_COVERAGE, save_ms->SampleAlphaToCoverage); + if (ctx_ms->SampleAlphaToOne != save_ms->SampleAlphaToOne) + _mesa_set_enable(ctx, GL_SAMPLE_ALPHA_TO_ONE, save_ms->SampleAlphaToOne); + if (ctx_ms->SampleCoverageValue != save_ms->SampleCoverageValue || + ctx_ms->SampleCoverageInvert != save_ms->SampleCoverageInvert) { + _mesa_SampleCoverage(save_ms->SampleCoverageValue, + save_ms->SampleCoverageInvert); + } + if (ctx_ms->SampleShading != save_ms->SampleShading) + _mesa_set_enable(ctx, GL_SAMPLE_SHADING, save_ms->SampleShading); + if (ctx_ms->SampleMask != save_ms->SampleMask) + _mesa_set_enable(ctx, GL_SAMPLE_MASK, save_ms->SampleMask); + if (ctx_ms->SampleMaskValue != save_ms->SampleMaskValue) + _mesa_SampleMaski(0, save_ms->SampleMaskValue); + if (ctx_ms->MinSampleShadingValue != save_ms->MinSampleShadingValue) + _mesa_MinSampleShading(save_ms->MinSampleShadingValue); } if (state & MESA_META_FRAMEBUFFER_SRGB) { @@ -1157,7 +1213,23 @@ _mesa_meta_end(struct gl_context *ctx) 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; } @@ -1212,7 +1284,7 @@ init_temp_texture(struct gl_context *ctx, struct temp_texture *tex) } static void -cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex) +cleanup_temp_texture(struct temp_texture *tex) { if (!tex->TexObj) return; @@ -1225,8 +1297,8 @@ cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex) * Return pointer to temp_texture info for non-bitmap ops. * This does some one-time init if needed. */ -static struct temp_texture * -get_temp_texture(struct gl_context *ctx) +struct temp_texture * +_mesa_meta_get_temp_texture(struct gl_context *ctx) { struct temp_texture *tex = &ctx->Meta->TempTex; @@ -1259,8 +1331,8 @@ get_bitmap_temp_texture(struct gl_context *ctx) * Return pointer to depth temp_texture. * This does some one-time init if needed. */ -static struct temp_texture * -get_temp_depth_texture(struct gl_context *ctx) +struct temp_texture * +_mesa_meta_get_temp_depth_texture(struct gl_context *ctx) { struct temp_texture *tex = &ctx->Meta->Blit.depthTex; @@ -1280,9 +1352,9 @@ get_temp_depth_texture(struct gl_context *ctx) * * \return GL_TRUE if new texture is needed, GL_FALSE otherwise */ -static GLboolean -alloc_texture(struct temp_texture *tex, - GLsizei width, GLsizei height, GLenum intFormat) +GLboolean +_mesa_meta_alloc_texture(struct temp_texture *tex, + GLsizei width, GLsizei height, GLenum intFormat) { GLboolean newTex = GL_FALSE; @@ -1333,19 +1405,22 @@ alloc_texture(struct temp_texture *tex, /** * Setup/load texture for glCopyPixels or glBlitFramebuffer. */ -static void -setup_copypix_texture(struct gl_context *ctx, - struct temp_texture *tex, - GLboolean newTex, - GLint srcX, GLint srcY, - GLsizei width, GLsizei height, GLenum intFormat, - GLenum filter) +void +_mesa_meta_setup_copypix_texture(struct gl_context *ctx, + struct temp_texture *tex, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height, + GLenum intFormat, + GLenum filter) { + bool newTex; + _mesa_BindTexture(tex->Target, tex->TexObj); _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, filter); _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, filter); - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + newTex = _mesa_meta_alloc_texture(tex, width, height, intFormat); /* copy framebuffer image to texture */ if (newTex) { @@ -1376,20 +1451,18 @@ setup_copypix_texture(struct gl_context *ctx, /** * Setup/load texture for glDrawPixels. */ -static void -setup_drawpix_texture(struct gl_context *ctx, - struct temp_texture *tex, - GLboolean newTex, - GLenum texIntFormat, - GLsizei width, GLsizei height, - GLenum format, GLenum type, - const GLvoid *pixels) +void +_mesa_meta_setup_drawpix_texture(struct gl_context *ctx, + struct temp_texture *tex, + GLboolean newTex, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels) { _mesa_BindTexture(tex->Target, tex->TexObj); _mesa_TexParameteri(tex->Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); _mesa_TexParameteri(tex->Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* copy pixel data to texture */ if (newTex) { @@ -1423,812 +1496,78 @@ setup_drawpix_texture(struct gl_context *ctx, } } +void +_mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO, + unsigned texcoord_size) +{ + _mesa_meta_setup_vertex_objects(VAO, VBO, false, 2, texcoord_size, 0); + /* setup projection matrix */ + _mesa_MatrixMode(GL_PROJECTION); + _mesa_LoadIdentity(); +} /** - * One-time init for drawing depth pixels. + * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. */ -static void -init_blit_depth_pixels(struct gl_context *ctx) +void +_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) { - static const char *program = - "!!ARBfp1.0\n" - "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" - "END \n"; - char program2[200]; - struct blit_state *blit = &ctx->Meta->Blit; - struct temp_texture *tex = get_temp_texture(ctx); - const char *texTarget; - - assert(blit->DepthFP == 0); - - /* replace %s with "RECT" or "2D" */ - assert(strlen(program) + 4 < sizeof(program2)); - if (tex->Target == GL_TEXTURE_RECTANGLE) - texTarget = "RECT"; - else - texTarget = "2D"; - _mesa_snprintf(program2, sizeof(program2), program, texTarget); - - _mesa_GenProgramsARB(1, &blit->DepthFP); - _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); - _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, - strlen(program2), (const GLubyte *) program2); + meta_clear(ctx, buffers, false); } -static void -setup_ff_blit_framebuffer(struct gl_context *ctx, - struct blit_state *blit) +void +_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) { - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - - if (blit->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &blit->ArrayObj); - _mesa_BindVertexArray(blit->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &blit->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - /* setup projection matrix */ - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); - + meta_clear(ctx, buffers, true); } static void -setup_glsl_blit_framebuffer(struct gl_context *ctx, - struct blit_state *blit, - GLenum target) +meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) { - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - const char *vs_source; - char *fs_source; + 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 *fs_source = + "uniform vec4 color;\n" + "void main()\n" + "{\n" + " gl_FragColor = color;\n" + "}\n"; GLuint vs, fs; - void *mem_ctx; - GLuint ShaderProg; - GLboolean texture_2d = (target == GL_TEXTURE_2D); + bool has_integer_textures; - /* target = GL_TEXTURE_RECTANGLE is not supported in GLES 3.0 */ - assert(_mesa_is_desktop_gl(ctx) || texture_2d); + _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, true, 3, 0, 0); - /* Check if already initialized */ - if (blit->ArrayObj == 0) { + if (clear->ShaderProg != 0) + return; - /* create vertex array object */ - _mesa_GenVertexArrays(1, &blit->ArrayObj); - _mesa_BindVertexArray(blit->ArrayObj); + vs = _mesa_CreateShader(GL_VERTEX_SHADER); + _mesa_ShaderSource(vs, 1, &vs_source, NULL); + _mesa_CompileShader(vs); - /* create vertex array buffer */ - _mesa_GenBuffers(1, &blit->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); - - /* setup vertex arrays */ - _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, - sizeof(struct vertex), OFFSET(x)); - _mesa_VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, - sizeof(struct vertex), OFFSET(s)); - - _mesa_EnableVertexAttribArray(0); - _mesa_EnableVertexAttribArray(1); - } - - /* Generate a relevant fragment shader program for the texture target */ - if ((target == GL_TEXTURE_2D && blit->ShaderProg != 0) || - (target == GL_TEXTURE_RECTANGLE && blit->RectShaderProg != 0)) { - return; - } - - mem_ctx = ralloc_context(NULL); - - if (ctx->Const.GLSLVersion < 130) { - vs_source = - "attribute vec2 position;\n" - "attribute vec2 textureCoords;\n" - "varying vec2 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, - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform %s texSampler;\n" - "varying vec2 texCoords;\n" - "void main()\n" - "{\n" - " gl_FragColor = %s(texSampler, texCoords);\n" - " gl_FragDepth = gl_FragColor.r;\n" - "}\n", - texture_2d ? "sampler2D" : "sampler2DRect", - texture_2d ? "texture2D" : "texture2DRect"); - } - else { - vs_source = ralloc_asprintf(mem_ctx, - "#version %s\n" - "in vec2 position;\n" - "in vec2 textureCoords;\n" - "out vec2 texCoords;\n" - "void main()\n" - "{\n" - " texCoords = textureCoords;\n" - " gl_Position = vec4(position, 0.0, 1.0);\n" - "}\n", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); - fs_source = ralloc_asprintf(mem_ctx, - "#version %s\n" - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform %s texSampler;\n" - "in vec2 texCoords;\n" - "out vec4 out_color;\n" - "\n" - "void main()\n" - "{\n" - " out_color = %s(texSampler, texCoords);\n" - " gl_FragDepth = out_color.r;\n" - "}\n", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es", - texture_2d ? "sampler2D" : "sampler2DRect", - texture_2d ? "texture" : "texture2DRect"); - } - - vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source); - fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source); - - ShaderProg = _mesa_CreateProgramObjectARB(); - _mesa_AttachShader(ShaderProg, fs); - _mesa_DeleteObjectARB(fs); - _mesa_AttachShader(ShaderProg, vs); - _mesa_DeleteObjectARB(vs); - _mesa_BindAttribLocation(ShaderProg, 0, "position"); - _mesa_BindAttribLocation(ShaderProg, 1, "texcoords"); - link_program_with_debug(ctx, ShaderProg); - ralloc_free(mem_ctx); - if (texture_2d) - blit->ShaderProg = ShaderProg; - else - blit->RectShaderProg = ShaderProg; -} - -/** - * Try to do a glBlitFramebuffer using no-copy texturing. - * We can do this when the src renderbuffer is actually a texture. - * But if the src buffer == dst buffer we cannot do this. - * - * \return new buffer mask indicating the buffers left to blit using the - * normal path. - */ -static GLbitfield -blitframebuffer_texture(struct gl_context *ctx, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter, GLint flipX, - GLint flipY, GLboolean glsl_version) -{ - if (mask & GL_COLOR_BUFFER_BIT) { - const struct gl_framebuffer *drawFb = ctx->DrawBuffer; - const struct gl_framebuffer *readFb = ctx->ReadBuffer; - const struct gl_renderbuffer_attachment *drawAtt; - const struct gl_renderbuffer_attachment *readAtt = - &readFb->Attachment[readFb->_ColorReadBufferIndex]; - - if (readAtt && readAtt->Texture) { - struct blit_state *blit = &ctx->Meta->Blit; - const GLint dstX = MIN2(dstX0, dstX1); - const GLint dstY = MIN2(dstY0, dstY1); - const GLint dstW = abs(dstX1 - dstX0); - const GLint dstH = abs(dstY1 - dstY0); - const struct gl_texture_object *texObj = readAtt->Texture; - const GLuint srcLevel = readAtt->TextureLevel; - const GLint baseLevelSave = texObj->BaseLevel; - const GLint maxLevelSave = texObj->MaxLevel; - const GLenum target = texObj->Target; - GLuint sampler, samplerSave = - ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? - ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; - int i; - - /* Iterate through all draw buffers */ - for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { - int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; - if (idx == -1) - continue; - drawAtt = &drawFb->Attachment[idx]; - - if (drawAtt->Texture == readAtt->Texture) { - /* Can't use same texture as both the source and dest. We need - * to handle overlapping blits and besides, some hw may not - * support this. - */ - return mask; - } - } - - if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) { - /* Can't handle other texture types at this time */ - return mask; - } - - /* Choose between glsl version and fixed function version of - * BlitFramebuffer function. - */ - if (glsl_version) { - setup_glsl_blit_framebuffer(ctx, blit, target); - if (target == GL_TEXTURE_2D) - _mesa_UseProgram(blit->ShaderProg); - else - _mesa_UseProgram(blit->RectShaderProg); - } - else { - setup_ff_blit_framebuffer(ctx, &ctx->Meta->Blit); - } - - _mesa_BindVertexArray(blit->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); - - _mesa_GenSamplers(1, &sampler); - _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler); - - /* - printf("Blit from texture!\n"); - printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); - printf(" srcTex %p dstText %p\n", texObj, drawAtt->Texture); - */ - - /* Prepare src texture state */ - _mesa_BindTexture(target, texObj->Name); - _mesa_SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, filter); - _mesa_SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, filter); - if (target != GL_TEXTURE_RECTANGLE_ARB) { - _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); - } - _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - _mesa_SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - /* Always do our blits with no sRGB decode or encode. Note that - * GL_FRAMEBUFFER_SRGB has already been disabled by - * _mesa_meta_begin(). - */ - if (ctx->Extensions.EXT_texture_sRGB_decode) { - _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, - GL_SKIP_DECODE_EXT); - } - - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) { - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - _mesa_set_enable(ctx, target, GL_TRUE); - } - - /* Prepare vertex data (the VBO was previously created and bound) */ - { - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - GLfloat s0, t0, s1, t1; - - if (target == GL_TEXTURE_2D) { - const struct gl_texture_image *texImage - = _mesa_select_tex_image(ctx, texObj, target, srcLevel); - s0 = srcX0 / (float) texImage->Width; - s1 = srcX1 / (float) texImage->Width; - t0 = srcY0 / (float) texImage->Height; - t1 = srcY1 / (float) texImage->Height; - } - else { - assert(target == GL_TEXTURE_RECTANGLE_ARB); - s0 = (float) srcX0; - s1 = (float) srcX1; - t0 = (float) srcY0; - t1 = (float) srcY1; - } - - /* setup vertex positions */ - verts[0].x = -1.0F * flipX; - verts[0].y = -1.0F * flipY; - verts[1].x = 1.0F * flipX; - verts[1].y = -1.0F * flipY; - verts[2].x = 1.0F * flipX; - verts[2].y = 1.0F * flipY; - verts[3].x = -1.0F * flipX; - verts[3].y = 1.0F * flipY; - - verts[0].s = s0; - verts[0].t = t0; - verts[1].s = s1; - verts[1].t = t0; - verts[2].s = s1; - verts[2].t = t1; - verts[3].s = s0; - verts[3].t = t1; - - _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - /* setup viewport */ - _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH); - _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - _mesa_DepthMask(GL_FALSE); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - - /* Restore texture object state, the texture binding will - * be restored by _mesa_meta_end(). - */ - if (target != GL_TEXTURE_RECTANGLE_ARB) { - _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); - } - - _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); - _mesa_DeleteSamplers(1, &sampler); - - /* Done with color buffer */ - mask &= ~GL_COLOR_BUFFER_BIT; - } - } - - return mask; -} - - -/** - * Meta implementation of ctx->Driver.BlitFramebuffer() in terms - * of texture mapping and polygon rendering. - */ -void -_mesa_meta_BlitFramebuffer(struct gl_context *ctx, - GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - struct blit_state *blit = &ctx->Meta->Blit; - struct temp_texture *tex = get_temp_texture(ctx); - struct temp_texture *depthTex = get_temp_depth_texture(ctx); - const GLsizei maxTexSize = tex->MaxSize; - const GLint srcX = MIN2(srcX0, srcX1); - const GLint srcY = MIN2(srcY0, srcY1); - const GLint srcW = abs(srcX1 - srcX0); - const GLint srcH = abs(srcY1 - srcY0); - const GLint dstX = MIN2(dstX0, dstX1); - const GLint dstY = MIN2(dstY0, dstY1); - const GLint dstW = abs(dstX1 - dstX0); - const GLint dstH = abs(dstY1 - dstY0); - const GLint srcFlipX = (srcX1 - srcX0) / srcW; - const GLint srcFlipY = (srcY1 - srcY0) / srcH; - const GLint dstFlipX = (dstX1 - dstX0) / dstW; - const GLint dstFlipY = (dstY1 - dstY0) / dstH; - const GLint flipX = srcFlipX * dstFlipX; - const GLint flipY = srcFlipY * dstFlipY; - - struct vertex { - GLfloat x, y, s, t; - }; - struct vertex verts[4]; - GLboolean newTex; - const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && - ctx->Extensions.ARB_fragment_shader && - (ctx->API != API_OPENGLES); - - /* In addition to falling back if the blit size is larger than the maximum - * texture size, fallback if the source is multisampled. This fallback can - * be removed once Mesa gets support ARB_texture_multisample. - */ - if (srcW > maxTexSize || srcH > maxTexSize - || ctx->ReadBuffer->Visual.samples > 0) { - /* XXX avoid this fallback */ - _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); - return; - } - - /* only scissor effects blit so save/clear all other relevant state */ - _mesa_meta_begin(ctx, ~MESA_META_SCISSOR); - - /* Try faster, direct texture approach first */ - mask = blitframebuffer_texture(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter, - dstFlipX, dstFlipY, use_glsl_version); - if (mask == 0x0) { - _mesa_meta_end(ctx); - return; - } - - /* Choose between glsl version and fixed function version of - * BlitFramebuffer function. - */ - if (use_glsl_version) { - setup_glsl_blit_framebuffer(ctx, blit, tex->Target); - if (tex->Target == GL_TEXTURE_2D) - _mesa_UseProgram(blit->ShaderProg); - else - _mesa_UseProgram(blit->RectShaderProg); - } - else { - setup_ff_blit_framebuffer(ctx, blit); - } - - _mesa_BindVertexArray(blit->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, blit->VBO); - - /* Continue with "normal" approach which involves copying the src rect - * into a temporary texture and is "blitted" by drawing a textured quad. - */ - { - /* setup vertex positions */ - verts[0].x = -1.0F * flipX; - verts[0].y = -1.0F * flipY; - verts[1].x = 1.0F * flipX; - verts[1].y = -1.0F * flipY; - verts[2].x = 1.0F * flipX; - verts[2].y = 1.0F * flipY; - verts[3].x = -1.0F * flipX; - verts[3].y = 1.0F * flipY; - - } - - /* glEnable() in gles2 and gles3 doesn't allow GL_TEXTURE_{1D, 2D, etc.} - * tokens. - */ - if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES) - _mesa_set_enable(ctx, tex->Target, GL_TRUE); - - if (mask & GL_COLOR_BUFFER_BIT) { - const struct gl_framebuffer *readFb = ctx->ReadBuffer; - const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; - const GLenum rb_base_format = - _mesa_base_tex_format(ctx, colorReadRb->InternalFormat); - - /* Using the exact source rectangle to create the texture does incorrect - * linear filtering along the edges. So, allocate the texture extended along - * edges by one pixel in x, y directions. - */ - newTex = alloc_texture(tex, srcW + 2, srcH + 2, rb_base_format); - setup_copypix_texture(ctx, tex, newTex, - srcX - 1, srcY - 1, srcW + 2, srcH + 2, - rb_base_format, filter); - /* texcoords (after texture allocation!) */ - { - verts[0].s = 1.0F; - verts[0].t = 1.0F; - verts[1].s = tex->Sright - 1.0F; - verts[1].t = 1.0F; - verts[2].s = tex->Sright - 1.0F; - verts[2].t = tex->Ttop - 1.0F; - verts[3].s = 1.0F; - verts[3].t = tex->Ttop - 1.0F; - - /* upload new vertex data */ - _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH); - _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); - _mesa_DepthMask(GL_FALSE); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - mask &= ~GL_COLOR_BUFFER_BIT; - } - - if ((mask & GL_DEPTH_BUFFER_BIT) && - _mesa_is_desktop_gl(ctx) && - ctx->Extensions.ARB_depth_texture && - ctx->Extensions.ARB_fragment_program) { - - GLuint *tmp = malloc(srcW * srcH * sizeof(GLuint)); - - if (tmp) { - - newTex = alloc_texture(depthTex, srcW, srcH, GL_DEPTH_COMPONENT); - _mesa_ReadPixels(srcX, srcY, srcW, srcH, GL_DEPTH_COMPONENT, - GL_UNSIGNED_INT, tmp); - setup_drawpix_texture(ctx, depthTex, newTex, GL_DEPTH_COMPONENT, - srcW, srcH, GL_DEPTH_COMPONENT, - GL_UNSIGNED_INT, tmp); - - /* texcoords (after texture allocation!) */ - { - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[1].s = depthTex->Sright; - verts[1].t = 0.0F; - verts[2].s = depthTex->Sright; - verts[2].t = depthTex->Ttop; - verts[3].s = 0.0F; - verts[3].t = depthTex->Ttop; - - /* upload new vertex data */ - _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - } - - if (!blit->DepthFP) - init_blit_depth_pixels(ctx); - - _mesa_BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); - _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); - _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); - _mesa_DepthFunc(GL_ALWAYS); - _mesa_DepthMask(GL_TRUE); - - _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH); - _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - mask &= ~GL_DEPTH_BUFFER_BIT; - - free(tmp); - } - } - - if (mask & GL_STENCIL_BUFFER_BIT) { - /* XXX can't easily do stencil */ - } - - if (_mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES) - _mesa_set_enable(ctx, tex->Target, GL_FALSE); - - _mesa_meta_end(ctx); - - if (mask) { - _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, mask, filter); - } -} - -static void -meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit) -{ - if (blit->ArrayObj) { - _mesa_DeleteVertexArrays(1, &blit->ArrayObj); - blit->ArrayObj = 0; - _mesa_DeleteBuffers(1, &blit->VBO); - blit->VBO = 0; - } - if (blit->DepthFP) { - _mesa_DeleteProgramsARB(1, &blit->DepthFP); - blit->DepthFP = 0; - } - - _mesa_DeleteObjectARB(blit->ShaderProg); - blit->ShaderProg = 0; - _mesa_DeleteObjectARB(blit->RectShaderProg); - blit->RectShaderProg = 0; - - _mesa_DeleteTextures(1, &blit->depthTex.TexObj); - blit->depthTex.TexObj = 0; -} - - -/** - * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. - */ -void -_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) -{ - struct clear_state *clear = &ctx->Meta->Clear; - struct vertex { - GLfloat x, y, z, r, g, b, a; - }; - 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); - - if (clear->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &clear->ArrayObj); - _mesa_BindVertexArray(clear->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &clear->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); - - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_COLOR_ARRAY); - } - else { - _mesa_BindVertexArray(clear->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); - } - - /* 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); - - _mesa_meta_end(ctx); -} - -static void -meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) -{ - const char *vs_source = - "attribute vec4 position;\n" - "void main()\n" - "{\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 = - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform vec4 color;\n" - "void main()\n" - "{\n" - " gl_FragColor = color;\n" - "}\n"; - GLuint vs, gs = 0, fs; - bool has_integer_textures; - - if (clear->ArrayObj != 0) - return; - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &clear->ArrayObj); - _mesa_BindVertexArray(clear->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &clear->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); - - /* setup vertex arrays */ - _mesa_VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); - _mesa_EnableVertexAttribArray(0); - - vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER); - _mesa_ShaderSource(vs, 1, &vs_source, NULL); - _mesa_CompileShader(vs); - - if (_mesa_has_geometry_shaders(ctx)) { - gs = _mesa_CreateShaderObjectARB(GL_GEOMETRY_SHADER); - _mesa_ShaderSource(gs, 1, &gs_source, NULL); - _mesa_CompileShader(gs); - } - - fs = _mesa_CreateShaderObjectARB(GL_FRAGMENT_SHADER); + fs = _mesa_CreateShader(GL_FRAGMENT_SHADER); _mesa_ShaderSource(fs, 1, &fs_source, NULL); _mesa_CompileShader(fs); - clear->ShaderProg = _mesa_CreateProgramObjectARB(); + clear->ShaderProg = _mesa_CreateProgram(); _mesa_AttachShader(clear->ShaderProg, fs); - _mesa_DeleteObjectARB(fs); - if (gs != 0) - _mesa_AttachShader(clear->ShaderProg, gs); + _mesa_DeleteShader(fs); _mesa_AttachShader(clear->ShaderProg, vs); - _mesa_DeleteObjectARB(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); @@ -2237,39 +1576,39 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) void *shader_source_mem_ctx = ralloc_context(NULL); const char *vs_int_source = ralloc_asprintf(shader_source_mem_ctx, - "#version %s\n" + "#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", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); + "}\n"); const char *fs_int_source = ralloc_asprintf(shader_source_mem_ctx, - "#version %s\n" - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" + "#version 130\n" "uniform ivec4 color;\n" "out ivec4 out_color;\n" "\n" "void main()\n" "{\n" " out_color = color;\n" - "}\n", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); + "}\n"); - vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source); - fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source); + vs = _mesa_meta_compile_shader_with_debug(ctx, GL_VERTEX_SHADER, + vs_int_source); + fs = _mesa_meta_compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, + fs_int_source); ralloc_free(shader_source_mem_ctx); - clear->IntegerShaderProg = _mesa_CreateProgramObjectARB(); + clear->IntegerShaderProg = _mesa_CreateProgram(); _mesa_AttachShader(clear->IntegerShaderProg, fs); - _mesa_DeleteObjectARB(fs); - if (gs != 0) - _mesa_AttachShader(clear->IntegerShaderProg, gs); + _mesa_DeleteShader(fs); _mesa_AttachShader(clear->IntegerShaderProg, vs); - _mesa_DeleteObjectARB(vs); + _mesa_DeleteShader(vs); _mesa_BindAttribLocation(clear->IntegerShaderProg, 0, "position"); /* Note that user-defined out attributes get automatically assigned @@ -2277,55 +1616,88 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) * BindFragDataLocation to 0. */ - link_program_with_debug(ctx, clear->IntegerShaderProg); + _mesa_ObjectLabel(GL_PROGRAM, clear->IntegerShaderProg, -1, + "integer clear"); + _mesa_meta_link_program_with_debug(ctx, clear->IntegerShaderProg); clear->IntegerColorLocation = _mesa_GetUniformLocation(clear->IntegerShaderProg, "color"); - if (gs != 0) { - clear->IntegerLayerLocation = - _mesa_GetUniformLocation(clear->IntegerShaderProg, "layer"); - } } - if (gs != 0) - _mesa_DeleteObjectARB(gs); } static void -meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear) +meta_glsl_clear_cleanup(struct clear_state *clear) { - if (clear->ArrayObj == 0) + if (clear->VAO == 0) return; - _mesa_DeleteVertexArrays(1, &clear->ArrayObj); - clear->ArrayObj = 0; + _mesa_DeleteVertexArrays(1, &clear->VAO); + clear->VAO = 0; _mesa_DeleteBuffers(1, &clear->VBO); clear->VBO = 0; - _mesa_DeleteObjectARB(clear->ShaderProg); + _mesa_DeleteProgram(clear->ShaderProg); clear->ShaderProg = 0; if (clear->IntegerShaderProg) { - _mesa_DeleteObjectARB(clear->IntegerShaderProg); + _mesa_DeleteProgram(clear->IntegerShaderProg); clear->IntegerShaderProg = 0; } } /** - * 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); - struct vertex { - GLfloat x, y, z; - } verts[4]; + float x0, y0, x1, y1, z; + struct vertex verts[4]; + int i; metaSave = (MESA_META_ALPHA_TEST | MESA_META_BLEND | @@ -2340,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 */ @@ -2349,24 +1732,41 @@ _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); } - _mesa_BindVertexArray(clear->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, clear->VBO); - /* 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) @@ -2414,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); } @@ -2445,13 +1847,8 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, GLint dstX, GLint dstY, GLenum type) { struct copypix_state *copypix = &ctx->Meta->CopyPix; - struct temp_texture *tex = get_temp_texture(ctx); - struct vertex { - GLfloat x, y, z, s, t; - }; + struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx); struct vertex verts[4]; - GLboolean newTex; - GLenum intFormat = GL_RGBA; if (type != GL_COLOR || ctx->_ImageTransferState || @@ -2474,31 +1871,15 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, MESA_META_VERTEX | MESA_META_VIEWPORT)); - if (copypix->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArrays(1, ©pix->ArrayObj); - _mesa_BindVertexArray(copypix->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, ©pix->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO); - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); + _mesa_meta_setup_vertex_objects(©pix->VAO, ©pix->VBO, false, + 3, 2, 0); - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - else { - _mesa_BindVertexArray(copypix->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, copypix->VBO); - } + /* Silence valgrind warnings about reading uninitialized stack. */ + memset(verts, 0, sizeof(verts)); - newTex = alloc_texture(tex, width, height, intFormat); + /* Alloc/setup texture */ + _mesa_meta_setup_copypix_texture(ctx, tex, srcX, srcY, width, height, + GL_RGBA, GL_NEAREST); /* vertex positions, texcoords (after texture allocation!) */ { @@ -2511,32 +1892,28 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, verts[0].x = dstX0; verts[0].y = dstY0; verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; + verts[0].tex[0] = 0.0F; + verts[0].tex[1] = 0.0F; verts[1].x = dstX1; verts[1].y = dstY0; verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; + verts[1].tex[0] = tex->Sright; + verts[1].tex[1] = 0.0F; verts[2].x = dstX1; verts[2].y = dstY1; verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; + verts[2].tex[0] = tex->Sright; + verts[2].tex[1] = tex->Ttop; verts[3].x = dstX0; verts[3].y = dstY1; verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; + verts[3].tex[0] = 0.0F; + verts[3].tex[1] = tex->Ttop; /* upload new vertex data */ _mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); } - /* Alloc/setup texture */ - setup_copypix_texture(ctx, tex, newTex, srcX, srcY, width, height, - GL_RGBA, GL_NEAREST); - _mesa_set_enable(ctx, tex->Target, GL_TRUE); /* draw textured quad */ @@ -2550,9 +1927,12 @@ _mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY, static void meta_drawpix_cleanup(struct drawpix_state *drawpix) { - if (drawpix->ArrayObj != 0) { - _mesa_DeleteVertexArrays(1, &drawpix->ArrayObj); - drawpix->ArrayObj = 0; + if (drawpix->VAO != 0) { + _mesa_DeleteVertexArrays(1, &drawpix->VAO); + drawpix->VAO = 0; + + _mesa_DeleteBuffers(1, &drawpix->VBO); + drawpix->VBO = 0; } if (drawpix->StencilFP != 0) { @@ -2648,7 +2028,7 @@ init_draw_stencil_pixels(struct gl_context *ctx) "END \n"; char program2[1000]; struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); + struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx); const char *texTarget; assert(drawpix->StencilFP == 0); @@ -2682,7 +2062,7 @@ init_draw_depth_pixels(struct gl_context *ctx) "END \n"; char program2[200]; struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); + struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx); const char *texTarget; assert(drawpix->DepthFP == 0); @@ -2714,17 +2094,13 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, const GLvoid *pixels) { struct drawpix_state *drawpix = &ctx->Meta->DrawPix; - struct temp_texture *tex = get_temp_texture(ctx); + struct temp_texture *tex = _mesa_meta_get_temp_texture(ctx); const struct gl_pixelstore_attrib unpackSave = ctx->Unpack; const GLuint origStencilMask = ctx->Stencil.WriteMask[0]; - struct vertex { - GLfloat x, y, z, s, t; - }; struct vertex verts[4]; GLenum texIntFormat; GLboolean fallback, newTex; GLbitfield metaExtraSave = 0x0; - GLuint vbo; /* * Determine if we can do the glDrawPixels with texture mapping. @@ -2814,7 +2190,13 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, MESA_META_VIEWPORT | metaExtraSave)); - newTex = alloc_texture(tex, width, height, texIntFormat); + newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat); + + _mesa_meta_setup_vertex_objects(&drawpix->VAO, &drawpix->VBO, false, + 3, 2, 0); + + /* Silence valgrind warnings about reading uninitialized stack. */ + memset(verts, 0, sizeof(verts)); /* vertex positions, texcoords (after texture allocation!) */ { @@ -2827,43 +2209,29 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, verts[0].x = x0; verts[0].y = y0; verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; + verts[0].tex[0] = 0.0F; + verts[0].tex[1] = 0.0F; verts[1].x = x1; verts[1].y = y0; verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; + verts[1].tex[0] = tex->Sright; + verts[1].tex[1] = 0.0F; verts[2].x = x1; verts[2].y = y1; verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; + verts[2].tex[0] = tex->Sright; + verts[2].tex[1] = tex->Ttop; verts[3].x = x0; verts[3].y = y1; verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; - } - - if (drawpix->ArrayObj == 0) { - /* one-time setup: create vertex array object */ - _mesa_GenVertexArrays(1, &drawpix->ArrayObj); + verts[3].tex[0] = 0.0F; + verts[3].tex[1] = tex->Ttop; } - _mesa_BindVertexArray(drawpix->ArrayObj); - /* create vertex array buffer */ - _mesa_GenBuffers(1, &vbo); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, vbo); + /* upload new vertex data */ _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts, GL_DYNAMIC_DRAW_ARB); - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - /* set given unpack params */ ctx->Unpack = *unpack; @@ -2876,8 +2244,8 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, if (!drawpix->StencilFP) init_draw_stencil_pixels(ctx); - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - GL_ALPHA, type, pixels); + _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height, + GL_ALPHA, type, pixels); _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -2919,22 +2287,20 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, ctx->Current.RasterColor); - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - format, type, pixels); + _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height, + format, type, pixels); _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } else { /* Drawing RGBA */ - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - format, type, pixels); + _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height, + format, type, pixels); _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } _mesa_set_enable(ctx, tex->Target, GL_FALSE); - _mesa_DeleteBuffers(1, &vbo); - /* restore unpack params */ ctx->Unpack = unpackSave; @@ -2986,9 +2352,6 @@ _mesa_meta_Bitmap(struct gl_context *ctx, const GLenum texIntFormat = GL_ALPHA; const struct gl_pixelstore_attrib unpackSave = *unpack; GLubyte fg, bg; - struct vertex { - GLfloat x, y, z, s, t, r, g, b, a; - }; struct vertex verts[4]; GLboolean newTex; GLubyte *bitmap8; @@ -2999,7 +2362,7 @@ _mesa_meta_Bitmap(struct gl_context *ctx, 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); @@ -3022,33 +2385,12 @@ _mesa_meta_Bitmap(struct gl_context *ctx, MESA_META_VERTEX | MESA_META_VIEWPORT)); - if (bitmap->ArrayObj == 0) { - /* one-time setup */ - - /* create vertex array object */ - _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj); - _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &bitmap->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO); - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); + _mesa_meta_setup_vertex_objects(&bitmap->VAO, &bitmap->VBO, false, 3, 2, 4); - /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_ColorPointer(4, GL_FLOAT, sizeof(struct vertex), OFFSET(r)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - _mesa_EnableClientState(GL_COLOR_ARRAY); - } - else { - _mesa_BindVertexArray(bitmap->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, bitmap->VBO); - } + newTex = _mesa_meta_alloc_texture(tex, width, height, texIntFormat); - newTex = alloc_texture(tex, width, height, texIntFormat); + /* Silence valgrind warnings about reading uninitialized stack. */ + memset(verts, 0, sizeof(verts)); /* vertex positions, texcoords, colors (after texture allocation!) */ { @@ -3062,23 +2404,23 @@ _mesa_meta_Bitmap(struct gl_context *ctx, verts[0].x = x0; verts[0].y = y0; verts[0].z = z; - verts[0].s = 0.0F; - verts[0].t = 0.0F; + verts[0].tex[0] = 0.0F; + verts[0].tex[1] = 0.0F; verts[1].x = x1; verts[1].y = y0; verts[1].z = z; - verts[1].s = tex->Sright; - verts[1].t = 0.0F; + verts[1].tex[0] = tex->Sright; + verts[1].tex[1] = 0.0F; verts[2].x = x1; verts[2].y = y1; verts[2].z = z; - verts[2].s = tex->Sright; - verts[2].t = tex->Ttop; + verts[2].tex[0] = tex->Sright; + verts[2].tex[1] = tex->Ttop; verts[3].x = x0; verts[3].y = y1; verts[3].z = z; - verts[3].s = 0.0F; - verts[3].t = tex->Ttop; + verts[3].tex[0] = 0.0F; + verts[3].tex[1] = tex->Ttop; for (i = 0; i < 4; i++) { verts[i].r = ctx->Current.RasterColor[0]; @@ -3112,8 +2454,8 @@ _mesa_meta_Bitmap(struct gl_context *ctx, _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE); _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg)); - setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height, - GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); + _mesa_meta_setup_drawpix_texture(ctx, tex, newTex, width, height, + GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -3127,102 +2469,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. @@ -3232,16 +2478,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[3], - GLfloat coords1[3], - GLfloat coords2[3], - GLfloat coords3[3]) +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} @@ -3249,6 +2495,16 @@ setup_texture_coords(GLenum faceTarget, 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; + coords1[3] = 1.0F; + coords2[3] = 1.0F; + coords3[3] = 1.0F; + switch (faceTarget) { case GL_TEXTURE_1D: case GL_TEXTURE_2D: @@ -3317,518 +2573,146 @@ setup_texture_coords(GLenum faceTarget, * Not +/-1 to avoid cube face selection ambiguity near the edges, * though that can still sometimes happen with this scale factor... */ - const GLfloat scale = 0.9999f; - const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale; - const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale; - GLfloat *coord; - - switch (i) { - case 0: - coord = coords0; - break; - case 1: - coord = coords1; - break; - case 2: - coord = coords2; - break; - case 3: - coord = coords3; - break; - default: - assert(0); - } - - switch (faceTarget) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - coord[0] = 1.0f; - coord[1] = -tc; - coord[2] = -sc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - coord[0] = -1.0f; - coord[1] = -tc; - coord[2] = sc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - coord[0] = sc; - coord[1] = 1.0f; - coord[2] = tc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - coord[0] = sc; - coord[1] = -1.0f; - coord[2] = -tc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - coord[0] = sc; - coord[1] = -tc; - coord[2] = 1.0f; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - coord[0] = -sc; - coord[1] = -tc; - coord[2] = -1.0f; - break; - default: - assert(0); - } - } - break; - default: - assert(0 && "unexpected target in meta setup_texture_coords()"); - } -} - - -static void -setup_ff_generate_mipmap(struct gl_context *ctx, - struct gen_mipmap_state *mipmap) -{ - struct vertex { - GLfloat x, y, tex[3]; - }; - - if (mipmap->ArrayObj == 0) { - /* one-time setup */ - /* create vertex array object */ - _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj); - _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &mipmap->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - /* setup projection matrix */ - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); -} - - -static struct glsl_sampler * -setup_texture_sampler(GLenum target, struct gen_mipmap_state *mipmap) -{ - switch(target) { - case GL_TEXTURE_1D: - mipmap->sampler_1d.type = "sampler1D"; - mipmap->sampler_1d.func = "texture1D"; - mipmap->sampler_1d.texcoords = "texCoords.x"; - return &mipmap->sampler_1d; - case GL_TEXTURE_2D: - mipmap->sampler_2d.type = "sampler2D"; - mipmap->sampler_2d.func = "texture2D"; - mipmap->sampler_2d.texcoords = "texCoords.xy"; - return &mipmap->sampler_2d; - case GL_TEXTURE_3D: - /* Code for mipmap generation with 3D textures is not used yet. - * It's a sw fallback. - */ - mipmap->sampler_3d.type = "sampler3D"; - mipmap->sampler_3d.func = "texture3D"; - mipmap->sampler_3d.texcoords = "texCoords"; - return &mipmap->sampler_3d; - case GL_TEXTURE_CUBE_MAP: - mipmap->sampler_cubemap.type = "samplerCube"; - mipmap->sampler_cubemap.func = "textureCube"; - mipmap->sampler_cubemap.texcoords = "texCoords"; - return &mipmap->sampler_cubemap; - case GL_TEXTURE_1D_ARRAY: - mipmap->sampler_1d_array.type = "sampler1DArray"; - mipmap->sampler_1d_array.func = "texture1DArray"; - mipmap->sampler_1d_array.texcoords = "texCoords.xy"; - return &mipmap->sampler_1d_array; - case GL_TEXTURE_2D_ARRAY: - mipmap->sampler_2d_array.type = "sampler2DArray"; - mipmap->sampler_2d_array.func = "texture2DArray"; - mipmap->sampler_2d_array.texcoords = "texCoords"; - return &mipmap->sampler_2d_array; - default: - _mesa_problem(NULL, "Unexpected texture target 0x%x in" - " setup_texture_sampler()\n", target); - return NULL; - } -} - - -static void -setup_glsl_generate_mipmap(struct gl_context *ctx, - struct gen_mipmap_state *mipmap, - GLenum target) -{ - struct vertex { - GLfloat x, y, tex[3]; - }; - struct glsl_sampler *sampler; - const char *vs_source; - char *fs_source; - GLuint vs, fs; - void *mem_ctx; - - /* Check if already initialized */ - if (mipmap->ArrayObj == 0) { - - /* create vertex array object */ - _mesa_GenVertexArrays(1, &mipmap->ArrayObj); - _mesa_BindVertexArray(mipmap->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &mipmap->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - - /* setup vertex arrays */ - _mesa_VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, - sizeof(struct vertex), OFFSET(x)); - _mesa_VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, - sizeof(struct vertex), OFFSET(tex)); - _mesa_EnableVertexAttribArray(0); - _mesa_EnableVertexAttribArray(1); - } - - /* Generate a fragment shader program appropriate for the texture target */ - sampler = setup_texture_sampler(target, mipmap); - assert(sampler != NULL); - if (sampler->shader_prog != 0) { - mipmap->ShaderProg = sampler->shader_prog; - return; - } - - mem_ctx = ralloc_context(NULL); - - if (ctx->API == API_OPENGLES2 || ctx->Const.GLSLVersion < 130) { - vs_source = - "attribute vec2 position;\n" - "attribute vec3 textureCoords;\n" - "varying vec3 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" - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform %s texSampler;\n" - "varying vec3 texCoords;\n" - "void main()\n" - "{\n" - " gl_FragColor = %s(texSampler, %s);\n" - "}\n", - sampler->type, - sampler->func, sampler->texcoords); - } - else { - vs_source = ralloc_asprintf(mem_ctx, - "#version %s\n" - "in vec2 position;\n" - "in vec3 textureCoords;\n" - "out vec3 texCoords;\n" - "void main()\n" - "{\n" - " texCoords = textureCoords;\n" - " gl_Position = vec4(position, 0.0, 1.0);\n" - "}\n", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es"); - fs_source = ralloc_asprintf(mem_ctx, - "#version %s\n" - "#ifdef GL_ES\n" - "precision highp float;\n" - "#endif\n" - "uniform %s texSampler;\n" - "in vec3 texCoords;\n" - "out vec4 out_color;\n" - "\n" - "void main()\n" - "{\n" - " out_color = texture(texSampler, %s);\n" - "}\n", - _mesa_is_desktop_gl(ctx) ? "130" : "300 es", - sampler->type, - sampler->texcoords); - } - - vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_source); - fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_source); - - mipmap->ShaderProg = _mesa_CreateProgramObjectARB(); - _mesa_AttachShader(mipmap->ShaderProg, fs); - _mesa_DeleteObjectARB(fs); - _mesa_AttachShader(mipmap->ShaderProg, vs); - _mesa_DeleteObjectARB(vs); - _mesa_BindAttribLocation(mipmap->ShaderProg, 0, "position"); - _mesa_BindAttribLocation(mipmap->ShaderProg, 1, "texcoords"); - link_program_with_debug(ctx, mipmap->ShaderProg); - sampler->shader_prog = mipmap->ShaderProg; - ralloc_free(mem_ctx); -} - - -static void -meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, - struct gen_mipmap_state *mipmap) -{ - if (mipmap->ArrayObj == 0) - return; - _mesa_DeleteVertexArrays(1, &mipmap->ArrayObj); - mipmap->ArrayObj = 0; - _mesa_DeleteBuffers(1, &mipmap->VBO); - mipmap->VBO = 0; - - _mesa_DeleteObjectARB(mipmap->sampler_1d.shader_prog); - _mesa_DeleteObjectARB(mipmap->sampler_2d.shader_prog); - _mesa_DeleteObjectARB(mipmap->sampler_3d.shader_prog); - _mesa_DeleteObjectARB(mipmap->sampler_cubemap.shader_prog); - _mesa_DeleteObjectARB(mipmap->sampler_1d_array.shader_prog); - _mesa_DeleteObjectARB(mipmap->sampler_2d_array.shader_prog); - - mipmap->sampler_1d.shader_prog = 0; - mipmap->sampler_2d.shader_prog = 0; - mipmap->sampler_3d.shader_prog = 0; - mipmap->sampler_cubemap.shader_prog = 0; - mipmap->sampler_1d_array.shader_prog = 0; - mipmap->sampler_2d_array.shader_prog = 0; -} - - -/** - * 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 { - GLfloat x, y, tex[3]; - }; - 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 && - (ctx->API != API_OPENGLES); - 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) { - setup_glsl_generate_mipmap(ctx, mipmap, target); - _mesa_UseProgram(mipmap->ShaderProg); - } - else { - setup_ff_generate_mipmap(ctx, mipmap); - _mesa_set_enable(ctx, target, GL_TRUE); - } - - _mesa_BindVertexArray(mipmap->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - - 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); - - if (ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGLES) - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); - else - assert(!genMipmapSave); - - /* 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); + const GLfloat scale = 0.9999f; + const GLfloat sc = (2.0f * st[i][0] - 1.0f) * scale; + const GLfloat tc = (2.0f * st[i][1] - 1.0f) * scale; + GLfloat *coord; - /* 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); - } + switch (i) { + case 0: + coord = coords0; + break; + case 1: + coord = coords1; + break; + case 2: + coord = coords2; + break; + case 3: + coord = coords3; + break; + default: + unreachable("not reached"); + } - _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + coord[3] = (float) (slice / 6); - /* 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; + switch (faceTarget) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + coord[0] = 1.0f; + coord[1] = -tc; + coord[2] = -sc; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + coord[0] = -1.0f; + coord[1] = -tc; + coord[2] = sc; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + coord[0] = sc; + coord[1] = 1.0f; + coord[2] = tc; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + coord[0] = sc; + coord[1] = -1.0f; + coord[2] = -tc; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + coord[0] = sc; + coord[1] = -tc; + coord[2] = 1.0f; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + coord[0] = -sc; + coord[1] = -tc; + coord[2] = -1.0f; + break; + default: + assert(0); + } } - - 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); + break; + default: + assert(!"unexpected target in _mesa_meta_setup_texture_coords()"); } +} - _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); +static struct blit_shader * +choose_blit_shader(GLenum target, struct blit_shader_table *table) +{ + switch(target) { + case GL_TEXTURE_1D: + table->sampler_1d.type = "sampler1D"; + table->sampler_1d.func = "texture1D"; + table->sampler_1d.texcoords = "texCoords.x"; + return &table->sampler_1d; + case GL_TEXTURE_2D: + table->sampler_2d.type = "sampler2D"; + table->sampler_2d.func = "texture2D"; + table->sampler_2d.texcoords = "texCoords.xy"; + return &table->sampler_2d; + case GL_TEXTURE_RECTANGLE: + table->sampler_rect.type = "sampler2DRect"; + table->sampler_rect.func = "texture2DRect"; + table->sampler_rect.texcoords = "texCoords.xy"; + return &table->sampler_rect; + case GL_TEXTURE_3D: + /* Code for mipmap generation with 3D textures is not used yet. + * It's a sw fallback. + */ + table->sampler_3d.type = "sampler3D"; + table->sampler_3d.func = "texture3D"; + table->sampler_3d.texcoords = "texCoords.xyz"; + return &table->sampler_3d; + case GL_TEXTURE_CUBE_MAP: + table->sampler_cubemap.type = "samplerCube"; + table->sampler_cubemap.func = "textureCube"; + table->sampler_cubemap.texcoords = "texCoords.xyz"; + return &table->sampler_cubemap; + case GL_TEXTURE_1D_ARRAY: + table->sampler_1d_array.type = "sampler1DArray"; + table->sampler_1d_array.func = "texture1DArray"; + table->sampler_1d_array.texcoords = "texCoords.xy"; + return &table->sampler_1d_array; + case GL_TEXTURE_2D_ARRAY: + table->sampler_2d_array.type = "sampler2DArray"; + table->sampler_2d_array.func = "texture2DArray"; + table->sampler_2d_array.texcoords = "texCoords.xyz"; + return &table->sampler_2d_array; + case GL_TEXTURE_CUBE_MAP_ARRAY: + table->sampler_cubemap_array.type = "samplerCubeArray"; + table->sampler_cubemap_array.func = "textureCubeArray"; + table->sampler_cubemap_array.texcoords = "texCoords.xyzw"; + return &table->sampler_cubemap_array; + default: + _mesa_problem(NULL, "Unexpected texture target 0x%x in" + " setup_texture_sampler()\n", target); + return NULL; + } } +void +_mesa_meta_blit_shader_table_cleanup(struct blit_shader_table *table) +{ + _mesa_DeleteProgram(table->sampler_1d.shader_prog); + _mesa_DeleteProgram(table->sampler_2d.shader_prog); + _mesa_DeleteProgram(table->sampler_3d.shader_prog); + _mesa_DeleteProgram(table->sampler_rect.shader_prog); + _mesa_DeleteProgram(table->sampler_cubemap.shader_prog); + _mesa_DeleteProgram(table->sampler_1d_array.shader_prog); + _mesa_DeleteProgram(table->sampler_2d_array.shader_prog); + _mesa_DeleteProgram(table->sampler_cubemap_array.shader_prog); + + table->sampler_1d.shader_prog = 0; + table->sampler_2d.shader_prog = 0; + table->sampler_3d.shader_prog = 0; + table->sampler_rect.shader_prog = 0; + table->sampler_cubemap.shader_prog = 0; + table->sampler_1d_array.shader_prog = 0; + table->sampler_2d_array.shader_prog = 0; + table->sampler_cubemap_array.shader_prog = 0; +} /** * Determine the GL data type to use for the temporary image read with @@ -3837,9 +2721,9 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, 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: @@ -3850,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); @@ -3881,6 +2759,86 @@ get_temp_image_type(struct gl_context *ctx, mesa_format format) } } +/** + * 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. @@ -3899,6 +2857,15 @@ _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims, GLint bpp; void *buf; + 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); if (format == GL_LUMINANCE || @@ -3965,17 +2932,25 @@ _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->ArrayObj != 0) { - _mesa_DeleteVertexArrays(1, &decompress->ArrayObj); + if (decompress->VAO != 0) { + _mesa_DeleteVertexArrays(1, &decompress->VAO); _mesa_DeleteBuffers(1, &decompress->VBO); } @@ -3994,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, @@ -4002,87 +2977,107 @@ 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 { - GLfloat x, y, tex[3]; - }; 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); + target == GL_TEXTURE_2D_ARRAY || + target == GL_TEXTURE_CUBE_MAP_ARRAY); } - if (target == GL_TEXTURE_CUBE_MAP) { + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY: + assert(!"No compressed 1D textures."); + return false; + + case GL_TEXTURE_3D: + assert(!"No compressed 3D textures."); + return false; + + case GL_TEXTURE_CUBE_MAP_ARRAY: + faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (slice % 6); + break; + + case GL_TEXTURE_CUBE_MAP: faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; - } - else { + break; + + default: faceTarget = target; + 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; } - /* setup VBO data */ - if (decompress->ArrayObj == 0) { - /* create vertex array object */ - _mesa_GenVertexArrays(1, &decompress->ArrayObj); - _mesa_BindVertexArray(decompress->ArrayObj); - - /* create vertex array buffer */ - _mesa_GenBuffers(1, &decompress->VBO); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO); - _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); + if (use_glsl_version) { + _mesa_meta_setup_vertex_objects(&decompress->VAO, &decompress->VBO, true, + 2, 4, 0); - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(tex)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); - } - else { - _mesa_BindVertexArray(decompress->ArrayObj); - _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, decompress->VBO); + _mesa_meta_setup_blit_shader(ctx, target, &decompress->shaders); + } else { + _mesa_meta_setup_ff_tnl_for_blit(&decompress->VAO, &decompress->VBO, 3); } if (!decompress->Sampler) { @@ -4101,25 +3096,25 @@ decompress_texture_image(struct gl_context *ctx, _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler); } - setup_texture_coords(faceTarget, slice, width, height, depth, - verts[0].tex, - verts[1].tex, - verts[2].tex, - verts[3].tex); + /* Silence valgrind warnings about reading uninitialized stack. */ + memset(verts, 0, sizeof(verts)); + + _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 = 0.0F; - verts[0].y = 0.0F; - verts[1].x = width; - verts[1].y = 0.0F; - verts[2].x = width; - verts[2].y = height; - verts[3].x = 0.0F; - verts[3].y = height; + 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; - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(0.0, width, 0.0, height, -1.0, 1.0); _mesa_set_viewport(ctx, 0, 0, 0, width, height); /* upload new vertex data */ @@ -4127,7 +3122,9 @@ decompress_texture_image(struct gl_context *ctx, /* setup texture state */ _mesa_BindTexture(target, texObj->Name); - _mesa_set_enable(ctx, target, GL_TRUE); + + if (!use_glsl_version) + _mesa_set_enable(ctx, target, GL_TRUE); { /* save texture object state */ @@ -4187,21 +3184,14 @@ decompress_texture_image(struct gl_context *ctx, } /* disable texture unit */ - _mesa_set_enable(ctx, target, GL_FALSE); + if (!use_glsl_version) + _mesa_set_enable(ctx, target, GL_FALSE); _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); _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; } @@ -4215,20 +3205,17 @@ _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++) { void *dst; - if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) { + if (texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY + || texImage->TexObject->Target == GL_TEXTURE_CUBE_MAP_ARRAY) { /* Setup pixel packing. SkipPixels and SkipRows will be applied * in the decompress_texture_image() function's call to * glReadPixels but we need to compute the dest slice's address @@ -4244,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); } @@ -4276,13 +3268,13 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, MESA_META_VERTEX | MESA_META_VIEWPORT)); - if (drawtex->ArrayObj == 0) { + if (drawtex->VAO == 0) { /* one-time setup */ GLint active_texture; /* create vertex array object */ - _mesa_GenVertexArrays(1, &drawtex->ArrayObj); - _mesa_BindVertexArray(drawtex->ArrayObj); + _mesa_GenVertexArrays(1, &drawtex->VAO); + _mesa_BindVertexArray(drawtex->VAO); /* create vertex array buffer */ _mesa_GenBuffers(1, &drawtex->VBO); @@ -4306,7 +3298,7 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, _mesa_ClientActiveTexture(GL_TEXTURE0 + active_texture); } else { - _mesa_BindVertexArray(drawtex->ArrayObj); + _mesa_BindVertexArray(drawtex->VAO); _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB, drawtex->VBO); } @@ -4340,7 +3332,7 @@ _mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, 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; @@ -4379,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); +}