mesa: move PBO-related functions into a new file
[mesa.git] / src / mesa / drivers / common / meta.c
index 1bfd76a665dfc73242461e01d579a92e47b47aff..2b00e8979d26a7cbcc7f3e614f777ef9a0f6e52f 100644 (file)
 #include "main/macros.h"
 #include "main/matrix.h"
 #include "main/mipmap.h"
+#include "main/pbo.h"
 #include "main/polygon.h"
 #include "main/readpix.h"
 #include "main/scissor.h"
 #include "main/shaderapi.h"
+#include "main/shaderobj.h"
 #include "main/state.h"
 #include "main/stencil.h"
 #include "main/texobj.h"
@@ -103,6 +105,8 @@ struct save_state
 
    /** META_ALPHA_TEST */
    GLboolean AlphaEnabled;
+   GLenum AlphaFunc;
+   GLclampf AlphaRef;
 
    /** META_BLEND */
    GLbitfield BlendEnabled;
@@ -143,10 +147,10 @@ struct save_state
    struct gl_vertex_program *VertexProgram;
    GLboolean FragmentProgramEnabled;
    struct gl_fragment_program *FragmentProgram;
-   GLuint VertexShader;
-   GLuint GeometryShader;
-   GLuint FragmentShader;
-   GLuint ActiveShader;
+   struct gl_shader_program *VertexShader;
+   struct gl_shader_program *GeometryShader;
+   struct gl_shader_program *FragmentShader;
+   struct gl_shader_program *ActiveShader;
 
    /** META_STENCIL_TEST */
    struct gl_stencil_attrib Stencil;
@@ -263,13 +267,16 @@ struct gen_mipmap_state
    GLuint FBO;
 };
 
-
+#define MAX_META_OPS_DEPTH      2
 /**
  * All per-context meta state.
  */
 struct gl_meta_state
 {
-   struct save_state Save;    /**< state saved during meta-ops */
+   /** Stack of state saved during meta-ops */
+   struct save_state Save[MAX_META_OPS_DEPTH];
+   /** Save stack depth */
+   GLuint SaveStackDepth;
 
    struct temp_texture TempTex;
 
@@ -321,12 +328,19 @@ _mesa_meta_free(struct gl_context *ctx)
 static void
 _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 {
-   struct save_state *save = &ctx->Meta->Save;
+   struct save_state *save;
+
+   /* hope MAX_META_OPS_DEPTH is large enough */
+   assert(ctx->Meta->SaveStackDepth < MAX_META_OPS_DEPTH);
 
+   save = &ctx->Meta->Save[ctx->Meta->SaveStackDepth++];
+   memset(save, 0, sizeof(*save));
    save->SavedState = state;
 
    if (state & META_ALPHA_TEST) {
       save->AlphaEnabled = ctx->Color.AlphaEnabled;
+      save->AlphaFunc = ctx->Color.AlphaFunc;
+      save->AlphaRef = ctx->Color.AlphaRef;
       if (ctx->Color.AlphaEnabled)
          _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE);
    }
@@ -436,14 +450,14 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
       }
 
       if (ctx->Extensions.ARB_shader_objects) {
-         save->VertexShader = ctx->Shader.CurrentVertexProgram ?
-            ctx->Shader.CurrentVertexProgram->Name : 0;
-         save->GeometryShader = ctx->Shader.CurrentGeometryProgram ?
-            ctx->Shader.CurrentGeometryProgram->Name : 0;
-         save->FragmentShader = ctx->Shader.CurrentFragmentProgram ?
-            ctx->Shader.CurrentFragmentProgram->Name : 0;
-         save->ActiveShader = ctx->Shader.ActiveProgram ?
-            ctx->Shader.ActiveProgram->Name : 0;
+        _mesa_reference_shader_program(ctx, &save->VertexShader,
+                                       ctx->Shader.CurrentVertexProgram);
+        _mesa_reference_shader_program(ctx, &save->GeometryShader,
+                                       ctx->Shader.CurrentGeometryProgram);
+        _mesa_reference_shader_program(ctx, &save->FragmentShader,
+                                       ctx->Shader.CurrentFragmentProgram);
+        _mesa_reference_shader_program(ctx, &save->ActiveShader,
+                                       ctx->Shader.CurrentFragmentProgram);
 
          _mesa_UseProgramObjectARB(0);
       }
@@ -473,7 +487,8 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
             _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);
-            _mesa_set_enable(ctx, GL_TEXTURE_CUBE_MAP, 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);
@@ -569,12 +584,13 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
 static void
 _mesa_meta_end(struct gl_context *ctx)
 {
-   struct save_state *save = &ctx->Meta->Save;
+   struct save_state *save = &ctx->Meta->Save[--ctx->Meta->SaveStackDepth];
    const GLbitfield state = save->SavedState;
 
    if (state & META_ALPHA_TEST) {
       if (ctx->Color.AlphaEnabled != save->AlphaEnabled)
          _mesa_set_enable(ctx, GL_ALPHA_TEST, save->AlphaEnabled);
+      _mesa_AlphaFunc(save->AlphaFunc, save->AlphaRef);
    }
 
    if (state & META_BLEND) {
@@ -675,16 +691,18 @@ _mesa_meta_end(struct gl_context *ctx)
       }
 
       if (ctx->Extensions.ARB_vertex_shader)
-        _mesa_UseShaderProgramEXT(GL_VERTEX_SHADER, save->VertexShader);
+        _mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader);
 
       if (ctx->Extensions.ARB_geometry_shader4)
-        _mesa_UseShaderProgramEXT(GL_GEOMETRY_SHADER_ARB,
-                                  save->GeometryShader);
+        _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
+                                 save->GeometryShader);
 
       if (ctx->Extensions.ARB_fragment_shader)
-        _mesa_UseShaderProgramEXT(GL_FRAGMENT_SHADER, save->FragmentShader);
+        _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER,
+                                 save->FragmentShader);
 
-      _mesa_ActiveProgramEXT(save->ActiveShader);
+      _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram,
+                                    save->ActiveShader);
    }
 
    if (state & META_STENCIL_TEST) {
@@ -1389,6 +1407,7 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
    struct vertex verts[4];
    /* save all state but scissor, pixel pack/unpack */
    GLbitfield metaSave = META_ALL - META_SCISSOR - META_PIXEL_STORE;
+   const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
 
    if (buffers & BUFFER_BITS_COLOR) {
       /* if clearing color buffers, don't save/restore colormask */
@@ -1444,7 +1463,7 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
       _mesa_StencilOpSeparate(GL_FRONT_AND_BACK,
                               GL_REPLACE, GL_REPLACE, GL_REPLACE);
       _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS,
-                                ctx->Stencil.Clear & 0x7fffffff,
+                                ctx->Stencil.Clear & stencilMax,
                                 ctx->Stencil.WriteMask[0]);
    }
    else {
@@ -1971,13 +1990,39 @@ _mesa_meta_DrawPixels(struct gl_context *ctx,
    _mesa_meta_end(ctx);
 }
 
+static GLboolean
+alpha_test_raster_color(struct gl_context *ctx)
+{
+   GLfloat alpha = ctx->Current.RasterColor[ACOMP];
+   GLfloat ref = ctx->Color.AlphaRef;
+
+   switch (ctx->Color.AlphaFunc) {
+      case GL_NEVER:
+        return GL_FALSE;
+      case GL_LESS:
+        return alpha < ref;
+      case GL_EQUAL:
+        return alpha == ref;
+      case GL_LEQUAL:
+        return alpha <= ref;
+      case GL_GREATER:
+        return alpha > ref;
+      case GL_NOTEQUAL:
+        return alpha != ref;
+      case GL_GEQUAL:
+        return alpha >= ref;
+      case GL_ALWAYS:
+        return GL_TRUE;
+      default:
+        assert(0);
+        return GL_FALSE;
+   }
+}
 
 /**
- * Do glBitmap with a alpha texture quad.  Use the alpha test to
- * cull the 'off' bits.  If alpha test is already enabled, fall back
- * to swrast (should be a rare case).
- * A bitmap cache as in the gallium/mesa state tracker would
- * improve performance a lot.
+ * Do glBitmap with a alpha texture quad.  Use the alpha test to cull
+ * the 'off' bits.  A bitmap cache as in the gallium/mesa state
+ * tracker would improve performance a lot.
  */
 void
 _mesa_meta_Bitmap(struct gl_context *ctx,
@@ -1989,6 +2034,7 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
    struct temp_texture *tex = get_bitmap_temp_texture(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;
    };
@@ -2000,7 +2046,7 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
     * Check if swrast fallback is needed.
     */
    if (ctx->_ImageTransferState ||
-       ctx->Color.AlphaEnabled ||
+       ctx->FragmentProgram._Enabled ||
        ctx->Fog.Enabled ||
        ctx->Texture._EnabledUnits ||
        width > tex->MaxSize ||
@@ -2009,6 +2055,9 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
       return;
    }
 
+   if (ctx->Color.AlphaEnabled && !alpha_test_raster_color(ctx))
+      return;
+
    /* Most GL state applies to glBitmap (like blending, stencil, etc),
     * but a there's a few things we need to override:
     */
@@ -2090,21 +2139,26 @@ _mesa_meta_Bitmap(struct gl_context *ctx,
       _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
    }
 
+   /* choose different foreground/background alpha values */
+   CLAMPED_FLOAT_TO_UBYTE(fg, ctx->Current.RasterColor[ACOMP]);
+   bg = (fg > 127 ? 0 : 255);
+
    bitmap1 = _mesa_map_pbo_source(ctx, &unpackSave, bitmap1);
    if (!bitmap1) {
       _mesa_meta_end(ctx);
       return;
    }
 
-   bitmap8 = (GLubyte *) calloc(1, width * height);
+   bitmap8 = (GLubyte *) malloc(width * height);
    if (bitmap8) {
+      memset(bitmap8, bg, width * height);
       _mesa_expand_bitmap(width, height, &unpackSave, bitmap1,
-                          bitmap8, width, 0xff);
+                          bitmap8, width, fg);
 
       _mesa_set_enable(ctx, tex->Target, GL_TRUE);
 
       _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE);
-      _mesa_AlphaFunc(GL_GREATER, 0.0);
+      _mesa_AlphaFunc(GL_NOTEQUAL, UBYTE_TO_FLOAT(bg));
 
       setup_drawpix_texture(ctx, tex, newTex, texIntFormat, width, height,
                             GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8);
@@ -2207,7 +2261,6 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
    const GLuint maxLevel = texObj->MaxLevel;
    const GLenum minFilterSave = texObj->MinFilter;
    const GLenum magFilterSave = texObj->MagFilter;
-   const GLint baseLevelSave = texObj->BaseLevel;
    const GLint maxLevelSave = texObj->MaxLevel;
    const GLboolean genMipmapSave = texObj->GenerateMipmap;
    const GLenum wrapSSave = texObj->WrapS;
@@ -2267,7 +2320,7 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
    }
    _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO);
 
-   _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   _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);
@@ -2443,8 +2496,7 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
          }
       }
 
-      /* limit sampling to src level */
-      _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, srcLevel);
+      /* limit minification to src level */
       _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);
 
       /* Set to draw into the current dstLevel */
@@ -2496,7 +2548,6 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
 
    _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave);
    _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave);
-   _mesa_TexParameteri(target, GL_TEXTURE_BASE_LEVEL, baseLevelSave);
    _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
    _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave);
    _mesa_TexParameteri(target, GL_TEXTURE_WRAP_S, wrapSSave);
@@ -2549,7 +2600,6 @@ copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
 {
    struct gl_texture_object *texObj;
    struct gl_texture_image *texImage;
-   GLsizei postConvWidth = width, postConvHeight = height;
    GLenum format, type;
    GLint bpp;
    void *buf;
@@ -2557,6 +2607,7 @@ copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
    texObj = _mesa_get_current_tex_object(ctx, target);
    texImage = _mesa_get_tex_image(ctx, texObj, target, level);
 
+   /* Choose format/type for temporary image buffer */
    format = _mesa_base_tex_format(ctx, internalFormat);
    type = get_temp_image_type(ctx, format);
    bpp = _mesa_bytes_per_pixel(format, type);
@@ -2588,12 +2639,8 @@ copy_tex_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
       ctx->Driver.FreeTexImageData(ctx, texImage);
    }
 
-   _mesa_init_teximage_fields(ctx, target, texImage,
-                              postConvWidth, postConvHeight, 1,
-                              border, internalFormat);
-
-   _mesa_choose_texture_format(ctx, texObj, texImage, target, level,
-                               internalFormat, GL_NONE, GL_NONE);
+   /* The texture's format was already chosen in _mesa_CopyTexImage() */
+   ASSERT(texImage->TexFormat != MESA_FORMAT_NONE);
 
    /*
     * Store texture data (with pixel transfer ops)
@@ -2646,7 +2693,8 @@ _mesa_meta_CopyTexImage2D(struct gl_context *ctx, GLenum target, GLint level,
  * 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,
+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)
@@ -2660,6 +2708,7 @@ copy_tex_sub_image(struct gl_context *ctx, GLuint dims, GLenum target, GLint lev
    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);
    type = get_temp_image_type(ctx, format);
    bpp = _mesa_bytes_per_pixel(format, type);