X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fdrivers%2Fcommon%2Fmeta.c;h=abb7d4e97fa8ba529b3686ada4537f23320840ec;hb=d1cf5c77b73d6b2c1cfd79ce0e3363e097177b6a;hp=291d912121b6b50eaae6c85fbc0a29562b73ca4a;hpb=f8e6d19f3f40931be741b44d3edf210c38e13f0f;p=mesa.git diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 291d912121b..abb7d4e97fa 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -44,11 +44,14 @@ #include "main/depth.h" #include "main/enable.h" #include "main/fbobject.h" +#include "main/feedback.h" #include "main/formats.h" +#include "main/glformats.h" #include "main/image.h" #include "main/macros.h" #include "main/matrix.h" #include "main/mipmap.h" +#include "main/pixel.h" #include "main/pbo.h" #include "main/polygon.h" #include "main/readpix.h" @@ -59,15 +62,20 @@ #include "main/stencil.h" #include "main/texobj.h" #include "main/texenv.h" +#include "main/texgetimage.h" #include "main/teximage.h" #include "main/texparam.h" #include "main/texstate.h" +#include "main/transformfeedback.h" #include "main/uniforms.h" #include "main/varray.h" #include "main/viewport.h" +#include "main/samplerobj.h" #include "program/program.h" #include "swrast/swrast.h" #include "drivers/common/meta.h" +#include "main/enums.h" +#include "main/glformats.h" /** Return offset in bytes of the field within a vertex struct */ @@ -170,11 +178,24 @@ struct save_state struct gl_query_object *CondRenderQuery; GLenum CondRenderMode; +#if FEATURE_feedback + /** MESA_META_SELECT_FEEDBACK */ + GLenum RenderMode; + struct gl_selection Select; + struct gl_feedback Feedback; +#endif + + /** MESA_META_MULTISAMPLE */ + GLboolean MultisampleEnabled; + /** Miscellaneous (always disabled) */ GLboolean Lighting; + GLboolean RasterDiscard; +#if FEATURE_EXT_transform_feedback + GLboolean TransformFeedbackNeedsResume; +#endif }; - /** * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. * This is currently shared by all the meta ops. But we could create a @@ -213,6 +234,9 @@ struct clear_state GLuint VBO; GLuint ShaderProg; GLint ColorLocation; + + GLuint IntegerShaderProg; + GLint IntegerColorLocation; }; @@ -257,9 +281,32 @@ struct gen_mipmap_state GLuint ArrayObj; GLuint VBO; GLuint FBO; + GLuint Sampler; + GLuint ShaderProg; + GLuint IntegerShaderProg; }; -#define MAX_META_OPS_DEPTH 2 + +/** + * State for texture decompression + */ +struct decompress_state +{ + GLuint ArrayObj; + GLuint VBO, FBO, RBO, Sampler; + GLint Width, Height; +}; + +/** + * State for glDrawTex() + */ +struct drawtex_state +{ + GLuint ArrayObj; + GLuint VBO; +}; + +#define MAX_META_OPS_DEPTH 8 /** * All per-context meta state. */ @@ -278,8 +325,82 @@ struct gl_meta_state 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 GLuint +compile_shader_with_debug(struct gl_context *ctx, GLenum target, const GLcharARB *source) +{ + GLuint shader; + GLint ok, size; + GLchar *info; + + shader = _mesa_CreateShaderObjectARB(target); + _mesa_ShaderSourceARB(shader, 1, &source, NULL); + _mesa_CompileShaderARB(shader); + + _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (ok) + return shader; + + _mesa_GetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); + if (size == 0) { + _mesa_DeleteObjectARB(shader); + return 0; + } + + info = malloc(size); + if (!info) { + _mesa_DeleteObjectARB(shader); + return 0; + } + + _mesa_GetProgramInfoLog(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); + + return 0; +} + +static GLuint +link_program_with_debug(struct gl_context *ctx, GLuint program) +{ + GLint ok, size; + GLchar *info; + + _mesa_LinkProgramARB(program); + + _mesa_GetProgramiv(program, GL_LINK_STATUS, &ok); + if (ok) + return program; + + _mesa_GetProgramiv(program, GL_INFO_LOG_LENGTH, &size); + if (size == 0) + return 0; + + info = malloc(size); + if (!info) + return 0; + + _mesa_GetProgramInfoLog(program, size, NULL, info); + _mesa_problem(ctx, "meta program link failed:\n%s", info); + + free(info); + + return 0; +} /** * Initialize meta-ops for a context. @@ -301,10 +422,16 @@ _mesa_meta_init(struct gl_context *ctx) void _mesa_meta_free(struct gl_context *ctx) { - /* Note: Any textures, VBOs, etc, that we allocate should get - * freed by the normal context destruction code. But this would be - * the place to free other meta data someday. - */ + 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); + if (old_context) + _mesa_make_current(old_context, old_context->WinSysDrawBuffer, old_context->WinSysReadBuffer); + else + _mesa_make_current(NULL, NULL, NULL); free(ctx->Meta); ctx->Meta = NULL; } @@ -329,6 +456,17 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) memset(save, 0, sizeof(*save)); save->SavedState = state; +#if FEATURE_EXT_transform_feedback + /* Pausing transform feedback needs to be done early, or else we won't be + * able to change other state. + */ + save->TransformFeedbackNeedsResume = + ctx->TransformFeedback.CurrentObject->Active && + !ctx->TransformFeedback.CurrentObject->Paused; + if (save->TransformFeedbackNeedsResume) + _mesa_PauseTransformFeedback(); +#endif + if (state & MESA_META_ALPHA_TEST) { save->AlphaEnabled = ctx->Color.AlphaEnabled; save->AlphaFunc = ctx->Color.AlphaFunc; @@ -416,8 +554,10 @@ _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); - _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, GL_FALSE); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, GL_FALSE); + if (ctx->API == API_OPENGL) { + _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); } @@ -427,14 +567,14 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) } if (state & MESA_META_SHADER) { - if (ctx->Extensions.ARB_vertex_program) { + if (ctx->API == API_OPENGL && 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->Extensions.ARB_fragment_program) { + if (ctx->API == API_OPENGL && ctx->Extensions.ARB_fragment_program) { save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled; _mesa_reference_fragprog(ctx, &save->FragmentProgram, ctx->FragmentProgram.Current); @@ -449,7 +589,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) _mesa_reference_shader_program(ctx, &save->FragmentShader, ctx->Shader.CurrentFragmentProgram); _mesa_reference_shader_program(ctx, &save->ActiveShader, - ctx->Shader.CurrentFragmentProgram); + ctx->Shader.ActiveProgram); _mesa_UseProgramObjectARB(0); } @@ -470,22 +610,27 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) save->EnvMode = ctx->Texture.Unit[0].EnvMode; /* Disable all texture units */ - 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_ActiveTextureARB(GL_TEXTURE0 + u); - _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); - _mesa_set_enable(ctx, GL_TEXTURE_3D, 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_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); + if (ctx->API == API_OPENGL || 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_ActiveTextureARB(GL_TEXTURE0 + u); + _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_FALSE); + _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_FALSE); + if (ctx->Extensions.ARB_texture_cube_map) + _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE); + if (ctx->Extensions.NV_texture_rectangle) + _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_FALSE); + if (ctx->Extensions.OES_EGL_image_external) + _mesa_set_enable(ctx, GL_TEXTURE_EXTERNAL_OES, 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); + } } } @@ -498,7 +643,9 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) /* set defaults for unit[0] */ _mesa_ActiveTextureARB(GL_TEXTURE0); _mesa_ClientActiveTextureARB(GL_TEXTURE0); - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + if (ctx->API == API_OPENGL || ctx->API == API_OPENGLES) { + _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } } if (state & MESA_META_TRANSFORM) { @@ -592,11 +739,33 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) _mesa_EndConditionalRender(); } +#if FEATURE_feedback + if (state & MESA_META_SELECT_FEEDBACK) { + save->RenderMode = ctx->RenderMode; + if (ctx->RenderMode == GL_SELECT) { + save->Select = ctx->Select; /* struct copy */ + _mesa_RenderMode(GL_RENDER); + } else if (ctx->RenderMode == GL_FEEDBACK) { + save->Feedback = ctx->Feedback; /* struct copy */ + _mesa_RenderMode(GL_RENDER); + } + } +#endif + + if (state & MESA_META_MULTISAMPLE) { + save->MultisampleEnabled = ctx->Multisample.Enabled; + if (ctx->Multisample.Enabled) + _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_FALSE); + } + /* misc */ { save->Lighting = ctx->Light.Enabled; if (ctx->Light.Enabled) _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE); + save->RasterDiscard = ctx->RasterDiscard; + if (ctx->RasterDiscard) + _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_FALSE); } } @@ -607,7 +776,7 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state) void _mesa_meta_end(struct gl_context *ctx) { - struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth]; + struct save_state *save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth - 1]; const GLbitfield state = save->SavedState; if (state & MESA_META_ALPHA_TEST) { @@ -682,11 +851,19 @@ _mesa_meta_end(struct gl_context *ctx) } if (state & MESA_META_RASTERIZATION) { - _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); - _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); - _mesa_set_enable(ctx, GL_POLYGON_STIPPLE, save->PolygonStipple); + /* 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) { + _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_POLYGON_SMOOTH, save->PolygonSmooth); _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull); } @@ -697,7 +874,7 @@ _mesa_meta_end(struct gl_context *ctx) } if (state & MESA_META_SHADER) { - if (ctx->Extensions.ARB_vertex_program) { + if (ctx->API == API_OPENGL && ctx->Extensions.ARB_vertex_program) { _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, save->VertexProgramEnabled); _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, @@ -705,7 +882,7 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_reference_vertprog(ctx, &save->VertexProgram, NULL); } - if (ctx->Extensions.ARB_fragment_program) { + if (ctx->API == API_OPENGL && ctx->Extensions.ARB_fragment_program) { _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, save->FragmentProgramEnabled); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, @@ -726,6 +903,11 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, save->ActiveShader); + + _mesa_reference_shader_program(ctx, &save->VertexShader, NULL); + _mesa_reference_shader_program(ctx, &save->GeometryShader, NULL); + _mesa_reference_shader_program(ctx, &save->FragmentShader, NULL); + _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL); } if (state & MESA_META_STENCIL_TEST) { @@ -733,7 +915,7 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled); _mesa_ClearStencil(stencil->Clear); - if (ctx->Extensions.EXT_stencil_two_side) { + if (ctx->API == API_OPENGL && ctx->Extensions.EXT_stencil_two_side) { _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT, stencil->TestTwoSide); _mesa_ActiveStencilFaceEXT(stencil->ActiveFace @@ -765,43 +947,32 @@ _mesa_meta_end(struct gl_context *ctx) ASSERT(ctx->Texture.CurrentUnit == 0); /* restore texenv for unit[0] */ - _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, save->EnvMode); + if (ctx->API == API_OPENGL || ctx->API == API_OPENGLES) { + _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++) { - _mesa_reference_texobj(&ctx->Texture.Unit[0].CurrentTex[tgt], - save->CurrentTexture[tgt]); + if (ctx->Texture.Unit[0].CurrentTex[tgt] != save->CurrentTexture[tgt]) { + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + _mesa_reference_texobj(&ctx->Texture.Unit[0].CurrentTex[tgt], + save->CurrentTexture[tgt]); + } _mesa_reference_texobj(&save->CurrentTexture[tgt], NULL); } - /* Re-enable textures, texgen */ - for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { - if (save->TexEnabled[u]) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + u); - - if (save->TexEnabled[u] & TEXTURE_1D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_1D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_2D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_2D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_3D_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_3D, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_CUBE_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, GL_TRUE); - if (save->TexEnabled[u] & TEXTURE_RECT_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_RECTANGLE, GL_TRUE); - } + /* Restore fixed function texture enables, texgen */ + if (ctx->API == API_OPENGL || 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]; + } - if (save->TexGenEnabled[u]) { - _mesa_ActiveTextureARB(GL_TEXTURE0 + u); - - if (save->TexGenEnabled[u] & S_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_S, GL_TRUE); - if (save->TexGenEnabled[u] & T_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_T, GL_TRUE); - if (save->TexGenEnabled[u] & R_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_R, GL_TRUE); - if (save->TexGenEnabled[u] & Q_BIT) - _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_TRUE); + if (ctx->Texture.Unit[u].TexGenEnabled != save->TexGenEnabled[u]) { + FLUSH_VERTICES(ctx, _NEW_TEXTURE); + ctx->Texture.Unit[u].TexGenEnabled = save->TexGenEnabled[u]; + } } } @@ -872,10 +1043,46 @@ _mesa_meta_end(struct gl_context *ctx) save->CondRenderMode); } +#if FEATURE_feedback + if (state & MESA_META_SELECT_FEEDBACK) { + if (save->RenderMode == GL_SELECT) { + _mesa_RenderMode(GL_SELECT); + ctx->Select = save->Select; + } else if (save->RenderMode == GL_FEEDBACK) { + _mesa_RenderMode(GL_FEEDBACK); + ctx->Feedback = save->Feedback; + } + } +#endif + + if (state & MESA_META_MULTISAMPLE) { + if (ctx->Multisample.Enabled != save->MultisampleEnabled) + _mesa_set_enable(ctx, GL_MULTISAMPLE, save->MultisampleEnabled); + } + /* misc */ if (save->Lighting) { _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE); } + if (save->RasterDiscard) { + _mesa_set_enable(ctx, GL_RASTERIZER_DISCARD, GL_TRUE); + } +#if FEATURE_EXT_transform_feedback + if (save->TransformFeedbackNeedsResume) + _mesa_ResumeTransformFeedback(); +#endif + + ctx->Meta->SaveStackDepth--; +} + + +/** + * Determine whether Mesa is currently in a meta state. + */ +GLboolean +_mesa_meta_in_progress(struct gl_context *ctx) +{ + return ctx->Meta->SaveStackDepth != 0; } @@ -889,7 +1096,7 @@ _mesa_meta_end(struct gl_context *ctx) static INLINE GLfloat invert_z(GLfloat normZ) { - GLfloat objZ = 1.0 - 2.0 * normZ; + GLfloat objZ = 1.0f - 2.0f * normZ; return objZ; } @@ -919,6 +1126,15 @@ init_temp_texture(struct gl_context *ctx, struct temp_texture *tex) _mesa_GenTextures(1, &tex->TexObj); } +static void +cleanup_temp_texture(struct gl_context *ctx, struct temp_texture *tex) +{ + if (!tex->TexObj) + return; + _mesa_DeleteTextures(1, &tex->TexObj); + tex->TexObj = 0; +} + /** * Return pointer to temp_texture info for non-bitmap ops. @@ -1163,15 +1379,13 @@ blitframebuffer_texture(struct gl_context *ctx, if (readAtt && readAtt->Texture) { const struct gl_texture_object *texObj = readAtt->Texture; const GLuint srcLevel = readAtt->TextureLevel; - const GLenum minFilterSave = texObj->Sampler.MinFilter; - const GLenum magFilterSave = texObj->Sampler.MagFilter; const GLint baseLevelSave = texObj->BaseLevel; const GLint maxLevelSave = texObj->MaxLevel; - const GLenum wrapSSave = texObj->Sampler.WrapS; - const GLenum wrapTSave = texObj->Sampler.WrapT; - const GLenum srgbSave = texObj->Sampler.sRGBDecode; const GLenum fbo_srgb_save = ctx->Color.sRGBEnabled; const GLenum target = texObj->Target; + GLuint sampler, samplerSave = + ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? + ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; if (drawAtt->Texture == readAtt->Texture) { /* Can't use same texture as both the source and dest. We need @@ -1186,6 +1400,9 @@ blitframebuffer_texture(struct gl_context *ctx, return mask; } + _mesa_GenSamplers(1, &sampler); + _mesa_BindSampler(ctx->Texture.CurrentUnit, sampler); + /* printf("Blit from texture!\n"); printf(" srcAtt %p dstAtt %p\n", readAtt, drawAtt); @@ -1194,21 +1411,24 @@ blitframebuffer_texture(struct gl_context *ctx, /* Prepare src texture state */ _mesa_BindTexture(target, texObj->Name); - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); + _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_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + _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.*/ if (ctx->Extensions.EXT_texture_sRGB_decode) { - _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, + _mesa_SamplerParameteri(sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); } - _mesa_Disable(GL_FRAMEBUFFER_SRGB_EXT); + if (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_framebuffer_sRGB + || _mesa_is_gles3(ctx)) { + _mesa_set_enable(ctx, GL_FRAMEBUFFER_SRGB_EXT, GL_FALSE); + } _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); _mesa_set_enable(ctx, target, GL_TRUE); @@ -1263,21 +1483,17 @@ blitframebuffer_texture(struct gl_context *ctx, /* Restore texture object state, the texture binding will * be restored by _mesa_meta_end(). */ - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); if (target != GL_TEXTURE_RECTANGLE_ARB) { _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); } - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); - if (ctx->Extensions.EXT_texture_sRGB_decode) { - _mesa_TexParameteri(target, GL_TEXTURE_SRGB_DECODE_EXT, srgbSave); - } - if (ctx->Extensions.EXT_texture_sRGB_decode && fbo_srgb_save) { - _mesa_Enable(GL_FRAMEBUFFER_SRGB_EXT); + if (ctx->Extensions.EXT_framebuffer_sRGB && fbo_srgb_save) { + _mesa_set_enable(ctx, GL_FRAMEBUFFER_SRGB_EXT, GL_TRUE); } + _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); + _mesa_DeleteSamplers(1, &sampler); + /* Done with color buffer */ mask &= ~GL_COLOR_BUFFER_BIT; } @@ -1312,7 +1528,12 @@ _mesa_meta_BlitFramebuffer(struct gl_context *ctx, struct vertex verts[4]; GLboolean newTex; - if (srcW > maxTexSize || srcH > maxTexSize) { + /* 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); @@ -1448,6 +1669,21 @@ _mesa_meta_BlitFramebuffer(struct gl_context *ctx, } } +static void +meta_glsl_blit_cleanup(struct gl_context *ctx, struct blit_state *blit) +{ + if (blit->ArrayObj) { + _mesa_DeleteVertexArraysAPPLE(1, &blit->ArrayObj); + blit->ArrayObj = 0; + _mesa_DeleteBuffersARB(1, &blit->VBO); + blit->VBO = 0; + } + if (blit->DepthFP) { + _mesa_DeletePrograms(1, &blit->DepthFP); + blit->DepthFP = 0; + } +} + /** * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering. @@ -1555,10 +1791,10 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers) /* vertex colors */ for (i = 0; i < 4; i++) { - verts[i].r = ctx->Color.ClearColorUnclamped[0]; - verts[i].g = ctx->Color.ClearColorUnclamped[1]; - verts[i].b = ctx->Color.ClearColorUnclamped[2]; - verts[i].a = ctx->Color.ClearColorUnclamped[3]; + 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 */ @@ -1587,6 +1823,22 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) "{\n" " gl_FragColor = color;\n" "}\n"; + const char *vs_int_source = + "#version 130\n" + "in vec4 position;\n" + "void main()\n" + "{\n" + " gl_Position = position;\n" + "}\n"; + const char *fs_int_source = + "#version 130\n" + "uniform ivec4 color;\n" + "out ivec4 out_color;\n" + "\n" + "void main()\n" + "{\n" + " out_color = color;\n" + "}\n"; GLuint vs, fs; if (clear->ArrayObj != 0) @@ -1614,12 +1866,54 @@ meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear) clear->ShaderProg = _mesa_CreateProgramObjectARB(); _mesa_AttachShader(clear->ShaderProg, fs); + _mesa_DeleteObjectARB(fs); _mesa_AttachShader(clear->ShaderProg, vs); + _mesa_DeleteObjectARB(vs); _mesa_BindAttribLocationARB(clear->ShaderProg, 0, "position"); _mesa_LinkProgramARB(clear->ShaderProg); clear->ColorLocation = _mesa_GetUniformLocationARB(clear->ShaderProg, "color"); + + if (_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130) { + vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source); + fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source); + + clear->IntegerShaderProg = _mesa_CreateProgramObjectARB(); + _mesa_AttachShader(clear->IntegerShaderProg, fs); + _mesa_DeleteObjectARB(fs); + _mesa_AttachShader(clear->IntegerShaderProg, vs); + _mesa_DeleteObjectARB(vs); + _mesa_BindAttribLocationARB(clear->IntegerShaderProg, 0, "position"); + + /* Note that user-defined out attributes get automatically assigned + * locations starting from 0, so we don't need to explicitly + * BindFragDataLocation to 0. + */ + + link_program_with_debug(ctx, clear->IntegerShaderProg); + + clear->IntegerColorLocation = + _mesa_GetUniformLocationARB(clear->IntegerShaderProg, "color"); + } +} + +static void +meta_glsl_clear_cleanup(struct gl_context *ctx, struct clear_state *clear) +{ + if (clear->ArrayObj == 0) + return; + _mesa_DeleteVertexArraysAPPLE(1, &clear->ArrayObj); + clear->ArrayObj = 0; + _mesa_DeleteBuffersARB(1, &clear->VBO); + clear->VBO = 0; + _mesa_DeleteObjectARB(clear->ShaderProg); + clear->ShaderProg = 0; + + if (clear->IntegerShaderProg) { + _mesa_DeleteObjectARB(clear->IntegerShaderProg); + clear->IntegerShaderProg = 0; + } } /** @@ -1650,7 +1944,8 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) MESA_META_VERTEX | MESA_META_VIEWPORT | MESA_META_CLIP | - MESA_META_CLAMP_FRAGMENT_COLOR); + MESA_META_CLAMP_FRAGMENT_COLOR | + MESA_META_MULTISAMPLE); if (!(buffers & BUFFER_BITS_COLOR)) { /* We'll use colormask to disable color writes. Otherwise, @@ -1663,9 +1958,15 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers) meta_glsl_clear_init(ctx, clear); - _mesa_UseProgramObjectARB(clear->ShaderProg); - _mesa_Uniform4fvARB(clear->ColorLocation, 1, - ctx->Color.ClearColorUnclamped); + if (fb->_IntegerColor) { + _mesa_UseProgramObjectARB(clear->IntegerShaderProg); + _mesa_Uniform4ivARB(clear->IntegerColorLocation, 1, + ctx->Color.ClearColor.i); + } else { + _mesa_UseProgramObjectARB(clear->ShaderProg); + _mesa_Uniform4fvARB(clear->ColorLocation, 1, + ctx->Color.ClearColor.f); + } _mesa_BindVertexArray(clear->ArrayObj); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); @@ -2007,8 +2308,7 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, * Determine if we can do the glDrawPixels with texture mapping. */ fallback = GL_FALSE; - if (ctx->_ImageTransferState || - ctx->Fog.Enabled) { + if (ctx->Fog.Enabled) { fallback = GL_TRUE; } @@ -2043,6 +2343,7 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, texIntFormat = GL_ALPHA; metaExtraSave = (MESA_META_COLOR_MASK | MESA_META_DEPTH_TEST | + MESA_META_PIXEL_TRANSFER | MESA_META_SHADER | MESA_META_STENCIL_TEST); } @@ -2089,7 +2390,6 @@ _mesa_meta_DrawPixels(struct gl_context *ctx, MESA_META_CLIP | MESA_META_VERTEX | MESA_META_VIEWPORT | - MESA_META_CLAMP_FRAGMENT_COLOR | metaExtraSave)); newTex = alloc_texture(tex, width, height, texIntFormat); @@ -2436,6 +2736,15 @@ _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, 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. + */ + return GL_TRUE; + } + /* * Test that we can actually render in the texture's format. */ @@ -2476,6 +2785,311 @@ _mesa_meta_check_generate_mipmap_fallback(struct gl_context *ctx, GLenum target, } +/** + * Compute the texture coordinates for the four vertices of a quad for + * drawing a 2D texture image or slice of a cube/3D texture. + * \param faceTarget GL_TEXTURE_1D/2D/3D or cube face name + * \param slice slice of a 1D/2D array texture or 3D texture + * \param width width of the texture image + * \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, + GLfloat coords0[3], + GLfloat coords1[3], + GLfloat coords2[3], + GLfloat coords3[3]) +{ + static const GLfloat st[4][2] = { + {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} + }; + GLuint i; + GLfloat r; + + switch (faceTarget) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + if (faceTarget == GL_TEXTURE_3D) + r = 1.0F / slice; + else if (faceTarget == GL_TEXTURE_2D_ARRAY) + r = slice; + else + r = 0.0F; + coords0[0] = 0.0F; /* s */ + coords0[1] = 0.0F; /* t */ + coords0[2] = r; /* r */ + coords1[0] = 1.0F; + coords1[1] = 0.0F; + coords1[2] = r; + coords2[0] = 1.0F; + coords2[1] = 1.0F; + coords2[2] = r; + coords3[0] = 0.0F; + coords3[1] = 1.0F; + coords3[2] = r; + break; + case GL_TEXTURE_RECTANGLE_ARB: + coords0[0] = 0.0F; /* s */ + coords0[1] = 0.0F; /* t */ + coords0[2] = 0.0F; /* r */ + coords1[0] = width; + coords1[1] = 0.0F; + coords1[2] = 0.0F; + coords2[0] = width; + coords2[1] = height; + coords2[2] = 0.0F; + coords3[0] = 0.0F; + coords3[1] = height; + coords3[2] = 0.0F; + break; + case GL_TEXTURE_1D_ARRAY: + coords0[0] = 0.0F; /* s */ + coords0[1] = slice; /* t */ + coords0[2] = 0.0F; /* r */ + coords1[0] = 1.0f; + coords1[1] = slice; + coords1[2] = 0.0F; + coords2[0] = 1.0F; + coords2[1] = slice; + coords2[2] = 0.0F; + coords3[0] = 0.0F; + coords3[1] = slice; + coords3[2] = 0.0F; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + /* loop over quad verts */ + for (i = 0; i < 4; i++) { + /* Compute sc = +/-scale and tc = +/-scale. + * 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_GenBuffersARB(1, &mipmap->VBO); + _mesa_BindBufferARB(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 void +setup_glsl_generate_mipmap(struct gl_context *ctx, + struct gen_mipmap_state *mipmap) +{ + struct vertex { + GLfloat x, y, tex[3]; + }; + + static const char *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"; + static const char *fs_source = + "uniform sampler2D tex2d;\n" + "varying vec3 texCoords;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(tex2d, texCoords.xy);\n" + "}\n"; + + static const char *vs_int_source = + "#version 130\n" + "in vec2 position;\n" + "in vec3 textureCoords;\n" + "out vec3 texCoords;\n" + "void main()\n" + "{\n" + " texCoords = textureCoords;\n" + " gl_Position = gl_Vertex;\n" + "}\n"; + static const char *fs_int_source = + "#version 130\n" + "uniform isampler2D tex2d;\n" + "in vec3 texCoords;\n" + "out ivec4 out_color;\n" + "\n" + "void main()\n" + "{\n" + " out_color = texture(tex2d, texCoords.xy);\n" + "}\n"; + GLuint vs, fs; + + /* Check if already initialized */ + if (mipmap->ArrayObj != 0) + return; + /* create vertex array object */ + _mesa_GenVertexArrays(1, &mipmap->ArrayObj); + _mesa_BindVertexArray(mipmap->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &mipmap->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + + /* setup vertex arrays */ + _mesa_VertexAttribPointerARB(0, 2, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), OFFSET(x)); + _mesa_VertexAttribPointerARB(1, 3, GL_FLOAT, GL_FALSE, + sizeof(struct vertex), OFFSET(tex)); + + 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_BindAttribLocationARB(mipmap->ShaderProg, 0, "position"); + _mesa_BindAttribLocationARB(mipmap->ShaderProg, 1, "texcoords"); + _mesa_EnableVertexAttribArrayARB(0); + _mesa_EnableVertexAttribArrayARB(1); + link_program_with_debug(ctx, mipmap->ShaderProg); + + if ((_mesa_is_desktop_gl(ctx) && ctx->Const.GLSLVersion >= 130) || + _mesa_is_gles3(ctx)){ + vs = compile_shader_with_debug(ctx, GL_VERTEX_SHADER, vs_int_source); + fs = compile_shader_with_debug(ctx, GL_FRAGMENT_SHADER, fs_int_source); + + mipmap->IntegerShaderProg = _mesa_CreateProgramObjectARB(); + _mesa_AttachShader(mipmap->IntegerShaderProg, fs); + _mesa_DeleteObjectARB(fs); + _mesa_AttachShader(mipmap->IntegerShaderProg, vs); + _mesa_DeleteObjectARB(vs); + _mesa_BindAttribLocationARB(mipmap->IntegerShaderProg, 0, "position"); + _mesa_BindAttribLocationARB(mipmap->IntegerShaderProg, 1, "texcoords"); + + /* Note that user-defined out attributes get automatically assigned + * locations starting from 0, so we don't need to explicitly + * BindFragDataLocation to 0. + */ + link_program_with_debug(ctx, mipmap->IntegerShaderProg); + } +} + + +static void +meta_glsl_generate_mipmap_cleanup(struct gl_context *ctx, + struct gen_mipmap_state *mipmap) +{ + if (mipmap->ArrayObj == 0) + return; + _mesa_DeleteVertexArraysAPPLE(1, &mipmap->ArrayObj); + mipmap->ArrayObj = 0; + _mesa_DeleteBuffersARB(1, &mipmap->VBO); + mipmap->VBO = 0; + _mesa_DeleteObjectARB(mipmap->ShaderProg); + mipmap->ShaderProg = 0; + + if (mipmap->IntegerShaderProg) { + _mesa_DeleteObjectARB(mipmap->IntegerShaderProg); + mipmap->IntegerShaderProg = 0; + } +} + + /** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, 1D/2D array textures or texture @@ -2487,23 +3101,23 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, { struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct vertex { - GLfloat x, y, s, t, r; + GLfloat x, y, tex[3]; }; struct vertex verts[4]; const GLuint baseLevel = texObj->BaseLevel; const GLuint maxLevel = texObj->MaxLevel; - const GLenum minFilterSave = texObj->Sampler.MinFilter; - const GLenum magFilterSave = texObj->Sampler.MagFilter; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; - const GLenum wrapSSave = texObj->Sampler.WrapS; - const GLenum wrapTSave = texObj->Sampler.WrapT; - const GLenum wrapRSave = texObj->Sampler.WrapR; + const GLenum srgbBufferSave = ctx->Color.sRGBEnabled; const GLuint fboSave = ctx->DrawBuffer->Name; - const GLuint original_active_unit = ctx->Texture.CurrentUnit; + 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; - GLuint border = 0; + const GLint slice = 0; + GLuint samplerSave; if (_mesa_meta_check_generate_mipmap_fallback(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); @@ -2521,144 +3135,101 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, _mesa_meta_begin(ctx, MESA_META_ALL); - if (original_active_unit != 0) - _mesa_BindTexture(target, texObj->Name); - - 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_GenBuffersARB(1, &mipmap->VBO); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), - NULL, GL_DYNAMIC_DRAW_ARB); + /* Choose between glsl version and fixed function version of + * GenerateMipmap function. + */ + if (use_glsl_version) { + setup_glsl_generate_mipmap(ctx, mipmap); - /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); - _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(s)); - _mesa_EnableClientState(GL_VERTEX_ARRAY); - _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + if (texObj->_IsIntegerFormat) + _mesa_UseProgramObjectARB(mipmap->IntegerShaderProg); + else + _mesa_UseProgramObjectARB(mipmap->ShaderProg); } else { - _mesa_BindVertexArray(mipmap->ArrayObj); - _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + setup_ff_generate_mipmap(ctx, mipmap); + _mesa_set_enable(ctx, target, GL_TRUE); } + _mesa_BindVertexArray(mipmap->ArrayObj); + _mesa_BindBufferARB(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_GenFramebuffersEXT(1, &mipmap->FBO); } - _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - _mesa_set_enable(ctx, target, GL_TRUE); - - /* setup texcoords once (XXX what about border?) */ - switch (faceTarget) { - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - verts[0].s = 0.0F; - verts[0].t = 0.0F; - verts[0].r = 0.0F; - verts[1].s = 1.0F; - verts[1].t = 0.0F; - verts[1].r = 0.0F; - verts[2].s = 1.0F; - verts[2].t = 1.0F; - verts[2].r = 0.0F; - verts[3].s = 0.0F; - verts[3].t = 1.0F; - verts[3].r = 0.0F; - break; - case GL_TEXTURE_3D: - abort(); - break; - default: - /* cube face */ - { - static const GLfloat st[4][2] = { - {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} - }; - GLuint i; + if (!mipmap->Sampler) { + _mesa_GenSamplers(1, &mipmap->Sampler); + _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); - /* loop over quad verts */ - for (i = 0; i < 4; i++) { - /* Compute sc = +/-scale and tc = +/-scale. - * 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; - - switch (faceTarget) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - verts[i].s = 1.0f; - verts[i].t = -tc; - verts[i].r = -sc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - verts[i].s = -1.0f; - verts[i].t = -tc; - verts[i].r = sc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - verts[i].s = sc; - verts[i].t = 1.0f; - verts[i].r = tc; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - verts[i].s = sc; - verts[i].t = -1.0f; - verts[i].r = -tc; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - verts[i].s = sc; - verts[i].t = -tc; - verts[i].r = 1.0f; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - verts[i].s = -sc; - verts[i].t = -tc; - verts[i].r = -1.0f; - break; - default: - assert(0); - } - } + if (use_glsl_version && texObj->_IsIntegerFormat) + _mesa_SamplerParameteri(mipmap->Sampler, + GL_TEXTURE_MIN_FILTER, + GL_NEAREST_MIPMAP_NEAREST); + else + _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_set_enable(ctx, target, GL_TRUE); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); - /* setup vertex positions */ - { - verts[0].x = 0.0F; - verts[0].y = 0.0F; - verts[1].x = 1.0F; - verts[1].y = 0.0F; - verts[2].x = 1.0F; - verts[2].y = 1.0F; - verts[3].x = 0.0F; - verts[3].y = 1.0F; - - /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + if (ctx->API == API_OPENGL || ctx->API == API_OPENGLES) + _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); + else + assert(!genMipmapSave); + + if ((ctx->Extensions.EXT_framebuffer_sRGB && + _mesa_is_desktop_gl(ctx)) || + _mesa_is_gles3(ctx)) { + _mesa_set_enable(ctx, GL_FRAMEBUFFER_SRGB_EXT, GL_FALSE); } - /* setup projection matrix */ - _mesa_MatrixMode(GL_PROJECTION); - _mesa_LoadIdentity(); - _mesa_Ortho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); + /* Setup texture coordinates */ + setup_texture_coords(faceTarget, + slice, + 0, 0, /* 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_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + verts, GL_DYNAMIC_DRAW_ARB); /* texture is already locked, unlock now */ _mesa_unlock_texture(ctx, texObj); @@ -2671,17 +3242,17 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, GLenum status; srcImage = _mesa_select_tex_image(ctx, texObj, faceTarget, srcLevel); - assert(srcImage->Border == 0); /* XXX we can fix this */ + assert(srcImage->Border == 0); - /* src size w/out border */ - srcWidth = srcImage->Width - 2 * border; - srcHeight = srcImage->Height - 2 * border; - srcDepth = srcImage->Depth - 2 * border; + /* src size */ + srcWidth = srcImage->Width; + srcHeight = srcImage->Height; + srcDepth = srcImage->Depth; - /* new dst size w/ border */ - dstWidth = MAX2(1, srcWidth / 2) + 2 * border; - dstHeight = MAX2(1, srcHeight / 2) + 2 * border; - dstDepth = MAX2(1, srcDepth / 2) + 2 * border; + /* 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 && @@ -2690,43 +3261,20 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, break; } - /* Set MaxLevel large enough to hold the new level when we allocate it */ + /* 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); - /* Create empty dest image */ - if (target == GL_TEXTURE_1D) { - _mesa_TexImage1D(target, dstLevel, srcImage->InternalFormat, - dstWidth, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - else if (target == GL_TEXTURE_3D) { - _mesa_TexImage3D(target, dstLevel, srcImage->InternalFormat, - dstWidth, dstHeight, dstDepth, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - else { - /* 2D or cube */ - _mesa_TexImage2D(faceTarget, dstLevel, srcImage->InternalFormat, - dstWidth, dstHeight, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - if (target == GL_TEXTURE_CUBE_MAP) { - /* If texturing from a cube, we need to make sure all src faces - * have been defined (even if we're not sampling from them.) - * Otherwise the texture object will be 'incomplete' and - * texturing from it will not be allowed. - */ - GLuint face; - for (face = 0; face < 6; face++) { - if (!texObj->Image[face][srcLevel] || - texObj->Image[face][srcLevel]->Width != srcWidth) { - _mesa_TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, - srcLevel, srcImage->InternalFormat, - srcWidth, srcHeight, border, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - } - } + 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 */ @@ -2762,7 +3310,8 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, /* sanity check */ status = _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - abort(); + _mesa_problem(ctx, "Unexpected incomplete framebuffer in " + "_mesa_meta_GenerateMipmap()"); break; } @@ -2775,17 +3324,19 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); } + if (ctx->Extensions.EXT_framebuffer_sRGB && srgbBufferSave) { + _mesa_set_enable(ctx, GL_FRAMEBUFFER_SRGB_EXT, GL_TRUE); + } + _mesa_lock_texture(ctx, texObj); /* relock */ + _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); + _mesa_meta_end(ctx); - _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); - _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); - _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_T, wrapTSave); - _mesa_TexParameteri(target, GL_TEXTURE_WRAP_R, wrapRSave); + if (genMipmapSave) + _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); } @@ -2796,27 +3347,34 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, * ReadPixels() and passed to Tex[Sub]Image(). */ static GLenum -get_temp_image_type(struct gl_context *ctx, GLenum baseFormat) +get_temp_image_type(struct gl_context *ctx, gl_format format) { + GLenum baseFormat; + + baseFormat = _mesa_get_format_base_format(format); + switch (baseFormat) { case GL_RGBA: case GL_RGB: + case GL_RG: + case GL_RED: case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: case GL_INTENSITY: if (ctx->DrawBuffer->Visual.redBits <= 8) return GL_UNSIGNED_BYTE; - else if (ctx->DrawBuffer->Visual.redBits <= 8) + else if (ctx->DrawBuffer->Visual.redBits <= 16) return GL_UNSIGNED_SHORT; else - return GL_FLOAT; + return _mesa_get_format_datatype(format); case GL_DEPTH_COMPONENT: return GL_UNSIGNED_INT; case GL_DEPTH_STENCIL: return GL_UNSIGNED_INT_24_8; default: - _mesa_problem(ctx, "Unexpected format in get_temp_image_type()"); + _mesa_problem(ctx, "Unexpected format %d in get_temp_image_type()", + baseFormat); return 0; } } @@ -2826,22 +3384,19 @@ get_temp_image_type(struct gl_context *ctx, GLenum baseFormat) * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. * Have to be careful with locking and meta state for pixel transfer. */ -static void -copy_tex_sub_image(struct gl_context *ctx, - GLuint dims, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) +void +_mesa_meta_CopyTexSubImage(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; - struct gl_texture_image *texImage; + struct gl_texture_object *texObj = texImage->TexObject; GLenum format, type; GLint bpp; void *buf; - texObj = _mesa_get_current_tex_object(ctx, target); - texImage = _mesa_select_tex_image(ctx, texObj, target, level); - /* Choose format/type for temporary image buffer */ format = _mesa_get_format_base_format(texImage->TexFormat); if (format == GL_LUMINANCE || @@ -2854,10 +3409,13 @@ copy_tex_sub_image(struct gl_context *ctx, format = GL_RGBA; } - type = get_temp_image_type(ctx, format); + type = get_temp_image_type(ctx, texImage->TexFormat); + if (_mesa_is_format_integer_color(texImage->TexFormat)) { + format = _mesa_base_format_to_integer_format(format); + } bpp = _mesa_bytes_per_pixel(format, type); if (bpp <= 0) { - _mesa_problem(ctx, "Bad bpp in meta copy_tex_sub_image()"); + _mesa_problem(ctx, "Bad bpp in _mesa_meta_CopyTexSubImage()"); return; } @@ -2886,21 +3444,11 @@ copy_tex_sub_image(struct gl_context *ctx, * Store texture data (with pixel transfer ops) */ _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE); - if (target == GL_TEXTURE_1D) { - ctx->Driver.TexSubImage1D(ctx, target, level, xoffset, - width, format, type, buf, - &ctx->Unpack, texObj, texImage); - } - else if (target == GL_TEXTURE_3D) { - ctx->Driver.TexSubImage3D(ctx, target, level, xoffset, yoffset, zoffset, - width, height, 1, format, type, buf, - &ctx->Unpack, texObj, texImage); - } - else { - ctx->Driver.TexSubImage2D(ctx, target, level, xoffset, yoffset, - width, height, format, type, buf, - &ctx->Unpack, texObj, texImage); - } + + ctx->Driver.TexSubImage(ctx, dims, texImage, + xoffset, yoffset, zoffset, width, height, 1, + format, type, buf, &ctx->Unpack); + _mesa_meta_end(ctx); _mesa_lock_texture(ctx, texObj); /* re-lock */ @@ -2909,88 +3457,369 @@ copy_tex_sub_image(struct gl_context *ctx, } -void -_mesa_meta_CopyTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, - GLint x, GLint y, GLsizei width) +/** + * Decompress a texture image by drawing a quad with the compressed + * texture and reading the pixels out of the color buffer. + * \param slice which slice of a 3D texture or layer of a 1D/2D texture + * \param destFormat format, ala glReadPixels + * \param destType type, ala glReadPixels + * \param dest destination buffer + * \param destRowLength dest image rowLength (ala GL_PACK_ROW_LENGTH) + */ +static void +decompress_texture_image(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLuint slice, + GLenum destFormat, GLenum destType, + GLvoid *dest) { - copy_tex_sub_image(ctx, 1, target, level, xoffset, 0, 0, - x, y, width, 1); -} + struct decompress_state *decompress = &ctx->Meta->Decompress; + struct gl_texture_object *texObj = texImage->TexObject; + const GLint width = texImage->Width; + const GLint height = texImage->Height; + const GLenum target = texObj->Target; + GLenum faceTarget; + struct vertex { + GLfloat x, y, tex[3]; + }; + struct vertex verts[4]; + GLuint fboDrawSave, fboReadSave; + GLuint rbSave; + GLuint samplerSave; + if (slice > 0) { + assert(target == GL_TEXTURE_3D || + target == GL_TEXTURE_2D_ARRAY); + } -void -_mesa_meta_CopyTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, GLint yoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) -{ - copy_tex_sub_image(ctx, 2, target, level, xoffset, yoffset, 0, - x, y, width, height); + if (target == GL_TEXTURE_CUBE_MAP) { + faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + texImage->Face; + } + else { + faceTarget = target; + } + + /* 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); + + 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_GenFramebuffersEXT(1, &decompress->FBO); + _mesa_GenRenderbuffersEXT(1, &decompress->RBO); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO); + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, decompress->RBO); + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, + decompress->RBO); + } + else { + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, decompress->FBO); + } + + /* alloc dest surface */ + if (width > decompress->Width || height > decompress->Height) { + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, decompress->RBO); + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, + width, height); + decompress->Width = width; + decompress->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_GenBuffersARB(1, &decompress->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO); + _mesa_BufferDataARB(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(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_BindBufferARB(GL_ARRAY_BUFFER_ARB, decompress->VBO); + } + + if (!decompress->Sampler) { + _mesa_GenSamplers(1, &decompress->Sampler); + _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler); + /* nearest filtering */ + _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + /* No sRGB decode or encode.*/ + if (ctx->Extensions.EXT_texture_sRGB_decode) { + _mesa_SamplerParameteri(decompress->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, + GL_SKIP_DECODE_EXT); + } + + } else { + _mesa_BindSampler(ctx->Texture.CurrentUnit, decompress->Sampler); + } + + setup_texture_coords(faceTarget, slice, width, height, + 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; + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + + /* setup texture state */ + _mesa_BindTexture(target, texObj->Name); + _mesa_set_enable(ctx, target, GL_TRUE); + + { + /* save texture object state */ + const GLint baseLevelSave = texObj->BaseLevel; + const GLint maxLevelSave = texObj->MaxLevel; + + /* restrict sampling to the texture level of interest */ + if (target != GL_TEXTURE_RECTANGLE_ARB) { + _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, texImage->Level); + _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, texImage->Level); + } + + /* No sRGB decode or encode.*/ + if (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_framebuffer_sRGB + || _mesa_is_gles3(ctx)) { + _mesa_set_enable(ctx, GL_FRAMEBUFFER_SRGB_EXT, GL_FALSE); + } + + /* render quad w/ texture into renderbuffer */ + _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); + } + + } + + /* read pixels from renderbuffer */ + { + GLenum baseTexFormat = texImage->_BaseFormat; + + /* The pixel transfer state will be set to default values at this point + * (see MESA_META_PIXEL_TRANSFER) so pixel transfer ops are effectively + * turned off (as required by glGetTexImage) but we need to handle some + * special cases. In particular, single-channel texture values are + * returned as red and two-channel texture values are returned as + * red/alpha. + */ + if (baseTexFormat == GL_LUMINANCE || + baseTexFormat == GL_LUMINANCE_ALPHA || + baseTexFormat == GL_INTENSITY) { + /* Green and blue must be zero */ + _mesa_PixelTransferf(GL_GREEN_SCALE, 0.0f); + _mesa_PixelTransferf(GL_BLUE_SCALE, 0.0f); + } + + _mesa_ReadPixels(0, 0, width, height, destFormat, destType, dest); + } + + /* disable texture unit */ + _mesa_set_enable(ctx, target, GL_FALSE); + + _mesa_BindSampler(ctx->Texture.CurrentUnit, samplerSave); + + _mesa_meta_end(ctx); + + /* restore fbo bindings */ + if (fboDrawSave == fboReadSave) { + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboDrawSave); + } + else { + _mesa_BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fboDrawSave); + _mesa_BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fboReadSave); + } + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbSave); } +/** + * This is just a wrapper around _mesa_get_tex_image() and + * decompress_texture_image(). Meta functions should not be directly called + * from core Mesa. + */ void -_mesa_meta_CopyTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLint x, GLint y, - GLsizei width, GLsizei height) +_mesa_meta_GetTexImage(struct gl_context *ctx, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_image *texImage) { - copy_tex_sub_image(ctx, 3, target, level, xoffset, yoffset, zoffset, - x, y, width, height); + /* 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) { + struct gl_texture_object *texObj = texImage->TexObject; + const GLuint slice = 0; /* only 2D compressed textures for now */ + /* Need to unlock the texture here to prevent deadlock... */ + _mesa_unlock_texture(ctx, texObj); + decompress_texture_image(ctx, texImage, slice, format, type, pixels); + /* ... and relock it */ + _mesa_lock_texture(ctx, texObj); + } + else { + _mesa_get_teximage(ctx, format, type, pixels, texImage); + } } +/** + * Meta implementation of ctx->Driver.DrawTex() in terms + * of polygon rendering. + */ void -_mesa_meta_CopyColorTable(struct gl_context *ctx, - GLenum target, GLenum internalformat, - GLint x, GLint y, GLsizei width) +_mesa_meta_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, + GLfloat width, GLfloat height) { - GLfloat *buf; +#if FEATURE_OES_draw_texture + struct drawtex_state *drawtex = &ctx->Meta->DrawTex; + struct vertex { + GLfloat x, y, z, st[MAX_TEXTURE_UNITS][2]; + }; + struct vertex verts[4]; + GLuint i; - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorTable"); - return; + _mesa_meta_begin(ctx, (MESA_META_RASTERIZATION | + MESA_META_SHADER | + MESA_META_TRANSFORM | + MESA_META_VERTEX | + MESA_META_VIEWPORT)); + + if (drawtex->ArrayObj == 0) { + /* one-time setup */ + GLint active_texture; + + /* create vertex array object */ + _mesa_GenVertexArrays(1, &drawtex->ArrayObj); + _mesa_BindVertexArray(drawtex->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &drawtex->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, drawtex->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* client active texture is not part of the array object */ + active_texture = ctx->Array.ActiveTexture; + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(struct vertex), OFFSET(x)); + _mesa_EnableClientState(GL_VERTEX_ARRAY); + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + _mesa_ClientActiveTextureARB(GL_TEXTURE0 + i); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(struct vertex), OFFSET(st[i])); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + /* restore client active texture */ + _mesa_ClientActiveTextureARB(GL_TEXTURE0 + active_texture); + } + else { + _mesa_BindVertexArray(drawtex->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, drawtex->VBO); } - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); + /* vertex positions, texcoords */ + { + const GLfloat x1 = x + width; + const GLfloat y1 = y + height; - _mesa_ColorTable(target, internalformat, width, GL_RGBA, GL_FLOAT, buf); + z = CLAMP(z, 0.0, 1.0); + z = invert_z(z); - _mesa_meta_end(ctx); + verts[0].x = x; + verts[0].y = y; + verts[0].z = z; - free(buf); -} + verts[1].x = x1; + verts[1].y = y; + verts[1].z = z; + verts[2].x = x1; + verts[2].y = y1; + verts[2].z = z; -void -_mesa_meta_CopyColorSubTable(struct gl_context *ctx,GLenum target, GLsizei start, - GLint x, GLint y, GLsizei width) -{ - GLfloat *buf; + verts[3].x = x; + verts[3].y = y1; + verts[3].z = z; - buf = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); - if (!buf) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyColorSubTable"); - return; - } + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + const struct gl_texture_object *texObj; + const struct gl_texture_image *texImage; + GLfloat s, t, s1, t1; + GLuint tw, th; + + if (!ctx->Texture.Unit[i]._ReallyEnabled) { + GLuint j; + for (j = 0; j < 4; j++) { + verts[j].st[i][0] = 0.0f; + verts[j].st[i][1] = 0.0f; + } + continue; + } - /* - * Read image from framebuffer (disable pixel transfer ops) - */ - _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); - ctx->Driver.ReadPixels(ctx, x, y, width, 1, - GL_RGBA, GL_FLOAT, &ctx->Pack, buf); + texObj = ctx->Texture.Unit[i]._Current; + texImage = texObj->Image[0][texObj->BaseLevel]; + tw = texImage->Width2; + th = texImage->Height2; - _mesa_ColorSubTable(target, start, width, GL_RGBA, GL_FLOAT, buf); + s = (GLfloat) texObj->CropRect[0] / tw; + t = (GLfloat) texObj->CropRect[1] / th; + s1 = (GLfloat) (texObj->CropRect[0] + texObj->CropRect[2]) / tw; + t1 = (GLfloat) (texObj->CropRect[1] + texObj->CropRect[3]) / th; - _mesa_meta_end(ctx); + verts[0].st[i][0] = s; + verts[0].st[i][1] = t; - free(buf); + verts[1].st[i][0] = s1; + verts[1].st[i][1] = t; + + verts[2].st[i][0] = s1; + verts[2].st[i][1] = t1; + + verts[3].st[i][0] = s; + verts[3].st[i][1] = t1; + } + + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_meta_end(ctx); +#endif /* FEATURE_OES_draw_texture */ }