Mesa (master): mesa: new driver meta-ops module

Brian Paul brianp at kemper.freedesktop.org
Mon Aug 10 19:59:38 UTC 2009


Module: Mesa
Branch: master
Commit: 33a838beb913c011b5ee8158c2717b7c8c351b17
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=33a838beb913c011b5ee8158c2717b7c8c351b17

Author: Brian Paul <brianp at vmware.com>
Date:   Mon Aug 10 13:35:58 2009 -0600

mesa: new driver meta-ops module

Implement glClear() in terms of quad rendering, implement glBlitFramebuffer()
in terms of glCopyTexImage2D + textured quad, etc.

There have been several places in the drivers where we've implemented
meta rendering similar to this.  This is an effort to do it in a more
portable and more efficient form.

The _mesa_meta_begin/end() functions act like glPush/PopAttrib() but are
lighter-weight.  Plus, _mesa_meta_begin() resets GL state back to default
values (texturing off, identity vertex transform, etc) so the meta drawing
functions don't have to worry about it.

For now only _mesa_mesa_blit_framebuffer() and _mesa_meta_clear() are
implemented.  glDrawPixels() and glCopyPixels() would be the next candidates.

---

 src/mesa/drivers/common/meta.c |  814 ++++++++++++++++++++++++++++++++++++++++
 src/mesa/drivers/common/meta.h |   67 ++++
 src/mesa/sources.mak           |    3 +-
 3 files changed, 883 insertions(+), 1 deletions(-)

diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
new file mode 100644
index 0000000..8123a76
--- /dev/null
+++ b/src/mesa/drivers/common/meta.c
@@ -0,0 +1,814 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.6
+ *
+ * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Meta operations.  Some GL operations can be expressed in terms of
+ * other GL operations.  For example, glBlitFramebuffer() can be done
+ * with texture mapping and glClear() can be done with polygon rendering.
+ *
+ * \author Brian Paul
+ */
+
+
+#include "main/glheader.h"
+#include "main/mtypes.h"
+#include "main/imports.h"
+#include "main/arrayobj.h"
+#include "main/blend.h"
+#include "main/bufferobj.h"
+#include "main/depth.h"
+#include "main/enable.h"
+#include "main/macros.h"
+#include "main/matrix.h"
+#include "main/polygon.h"
+#include "main/scissor.h"
+#include "main/shaders.h"
+#include "main/stencil.h"
+#include "main/texobj.h"
+#include "main/texenv.h"
+#include "main/teximage.h"
+#include "main/texparam.h"
+#include "main/texstate.h"
+#include "main/varray.h"
+#include "main/viewport.h"
+#include "shader/program.h"
+#include "swrast/swrast.h"
+#include "drivers/common/meta.h"
+
+
+/**
+ * State which we may save/restore across meta ops.
+ * XXX this may be incomplete...
+ */
+struct save_state
+{
+   GLbitfield SavedState;  /**< bitmask of META_* flags */
+
+   /** META_ALPHA_TEST */
+   GLboolean AlphaEnabled;
+
+   /** META_BLEND */
+   GLboolean BlendEnabled;
+   GLboolean ColorLogicOpEnabled;
+
+   /** META_COLOR_MASK */
+   GLubyte ColorMask[4];
+
+   /** META_DEPTH_TEST */
+   struct gl_depthbuffer_attrib Depth;
+
+   /** META_PIXELSTORE */
+   /* XXX / TO-DO */
+
+   /** META_RASTERIZATION */
+   GLenum FrontPolygonMode, BackPolygonMode;
+   GLboolean PolygonOffset;
+   GLboolean PolygonSmooth;
+   GLboolean PolygonStipple;
+   GLboolean PolygonCull;
+
+   /** META_SCISSOR */
+   struct gl_scissor_attrib Scissor;
+
+   /** META_SHADER */
+   GLboolean VertexProgramEnabled;
+   struct gl_vertex_program *VertexProgram;
+   GLboolean FragmentProgramEnabled;
+   struct gl_fragment_program *FragmentProgram;
+   GLuint Shader;
+
+   /** META_STENCIL_TEST */
+   struct gl_stencil_attrib Stencil;
+
+   /** META_TRANSFORM */
+   GLenum MatrixMode;
+   GLfloat ModelviewMatrix[16];
+   GLfloat ProjectionMatrix[16];
+   GLbitfield ClipPlanesEnabled;
+
+   /** 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 */
+
+   /** META_VERTEX */
+   struct gl_array_object *ArrayObj;
+   struct gl_buffer_object *ArrayBufferObj;
+
+   /** META_VIEWPORT */
+   GLint ViewportX, ViewportY, ViewportW, ViewportH;
+   GLclampd DepthNear, DepthFar;
+
+   /** Miscellaneous (always disabled) */
+   GLboolean Lighting;
+   GLboolean Fog;
+};
+
+
+/**
+ * State for glBlitFramebufer()
+ */
+struct blit_state
+{
+   GLuint TexObj;
+   GLuint ArrayObj;
+   GLuint VBO;
+   GLfloat verts[4][4]; /** four verts of X,Y,S,T */
+};
+
+
+/**
+ * State for glClear()
+ */
+struct clear_state
+{
+   GLuint ArrayObj;
+   GLuint VBO;
+   GLfloat verts[4][7]; /** four verts of X,Y,Z,R,G,B,A */
+};
+
+
+/**
+ * All per-context meta state.
+ */
+struct gl_meta_state
+{
+   struct save_state Save;    /**< state saved during meta-ops */
+
+   struct blit_state Blit;    /**< For _mesa_meta_blit_framebuffer() */
+   struct clear_state Clear;  /**< For _mesa_meta_clear() */
+
+   /* other possible meta-ops:
+    * glDrawPixels()
+    * glCopyPixels()
+    * glBitmap()
+    */
+};
+
+
+/**
+ * Initialize meta-ops for a context.
+ * To be called once during context creation.
+ */
+void
+_mesa_meta_init(GLcontext *ctx)
+{
+   ASSERT(!ctx->Meta);
+
+   ctx->Meta = CALLOC_STRUCT(gl_meta_state);
+}
+
+
+/**
+ * Free context meta-op state.
+ * To be called once during context destruction.
+ */
+void
+_mesa_meta_free(GLcontext *ctx)
+{
+   struct gl_meta_state *meta = ctx->Meta;
+
+   if (meta->Blit.TexObj) {
+      _mesa_DeleteTextures(1, &meta->Blit.TexObj);
+      _mesa_DeleteBuffersARB(1, & meta->Blit.VBO);
+      _mesa_DeleteVertexArraysAPPLE(1, &meta->Blit.ArrayObj);
+   }
+
+   if (meta->Clear.VBO) {
+      _mesa_DeleteBuffersARB(1, & meta->Clear.VBO);
+      _mesa_DeleteVertexArraysAPPLE(1, &meta->Clear.ArrayObj);
+   }
+
+   _mesa_free(ctx->Meta);
+   ctx->Meta = NULL;
+}
+
+
+/**
+ * Enter meta state.  This is like a light-weight version of glPushAttrib
+ * but it also resets most GL state back to default values.
+ *
+ * \param state  bitmask of META_* flags indicating which attribute groups
+ *               to save and reset to their defaults
+ */
+static void
+_mesa_meta_begin(GLcontext *ctx, GLbitfield state)
+{
+   struct save_state *save = &ctx->Meta->Save;
+
+   save->SavedState = state;
+
+   if (state & META_ALPHA_TEST) {
+      save->AlphaEnabled = ctx->Color.AlphaEnabled;
+      if (ctx->Color.AlphaEnabled)
+         _mesa_Disable(GL_ALPHA_TEST);
+   }
+
+   if (state & META_BLEND) {
+      save->BlendEnabled = ctx->Color.BlendEnabled;
+      if (ctx->Color.BlendEnabled)
+         _mesa_Disable(GL_BLEND);
+      save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled;
+      if (ctx->Color.ColorLogicOpEnabled)
+         _mesa_Disable(GL_COLOR_LOGIC_OP);
+   }
+
+   if (state & META_COLOR_MASK) {
+      COPY_4V(save->ColorMask, ctx->Color.ColorMask);
+      if (!ctx->Color.ColorMask[0] ||
+          !ctx->Color.ColorMask[1] ||
+          !ctx->Color.ColorMask[2] ||
+          !ctx->Color.ColorMask[3])
+         _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+   }
+
+   if (state & META_DEPTH_TEST) {
+      save->Depth = ctx->Depth; /* struct copy */
+      if (ctx->Depth.Test)
+         _mesa_Disable(GL_DEPTH_TEST);
+   }
+
+   if (state & META_RASTERIZATION) {
+      save->FrontPolygonMode = ctx->Polygon.FrontMode;
+      save->BackPolygonMode = ctx->Polygon.BackMode;
+      save->PolygonOffset = ctx->Polygon.OffsetFill;
+      save->PolygonSmooth = ctx->Polygon.SmoothFlag;
+      save->PolygonStipple = ctx->Polygon.StippleFlag;
+      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);
+      _mesa_set_enable(ctx, GL_CULL_FACE, GL_FALSE);
+   }
+
+   if (state & META_SCISSOR) {
+      save->Scissor = ctx->Scissor; /* struct copy */
+   }
+
+   if (state & META_SHADER) {
+      if (ctx->Extensions.ARB_vertex_program) {
+         save->VertexProgramEnabled = ctx->VertexProgram.Enabled;
+         save->VertexProgram = ctx->VertexProgram.Current;
+         _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB, GL_FALSE);
+      }
+
+      if (ctx->Extensions.ARB_fragment_program) {
+         save->FragmentProgramEnabled = ctx->FragmentProgram.Enabled;
+         save->FragmentProgram = ctx->FragmentProgram.Current;
+         _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_FALSE);
+      }
+
+      if (ctx->Extensions.ARB_shader_objects) {
+         save->Shader = ctx->Shader.CurrentProgram ?
+            ctx->Shader.CurrentProgram->Name : 0;
+         _mesa_UseProgramObjectARB(0);
+      }
+   }
+
+   if (state & META_STENCIL_TEST) {
+      save->Stencil = ctx->Stencil; /* struct copy */
+      if (ctx->Stencil.Enabled)
+         _mesa_Disable(GL_STENCIL_TEST);
+      /* NOTE: other stencil state not reset */
+   }
+
+   if (state & META_TEXTURE) {
+      GLuint u, tgt;
+
+      save->ActiveUnit = ctx->Texture.CurrentUnit;
+      save->ClientActiveUnit = ctx->Array.ActiveTexture;
+      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;
+         _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);
+         _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);
+      }
+
+      /* save current texture objects for unit[0] only */
+      for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
+         _mesa_reference_texobj(&save->CurrentTexture[tgt],
+                                ctx->Texture.Unit[0].CurrentTex[tgt]);
+      }
+
+      /* set defaults for unit[0] */
+      _mesa_ActiveTextureARB(GL_TEXTURE0);
+      _mesa_ClientActiveTextureARB(GL_TEXTURE0);
+      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+      _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 (state & META_TRANSFORM) {
+      _mesa_memcpy(save->ModelviewMatrix, ctx->ModelviewMatrixStack.Top->m,
+                   16 * sizeof(GLfloat));
+      _mesa_memcpy(save->ProjectionMatrix, ctx->ProjectionMatrixStack.Top->m,
+                   16 * sizeof(GLfloat));
+      save->MatrixMode = ctx->Transform.MatrixMode;
+      /* set 1:1 vertex:pixel coordinate transform */
+      _mesa_MatrixMode(GL_MODELVIEW);
+      _mesa_LoadIdentity();
+      _mesa_MatrixMode(GL_PROJECTION);
+      _mesa_LoadIdentity();
+      _mesa_Ortho(0.0F, ctx->DrawBuffer->Width,
+                  0.0F, ctx->DrawBuffer->Height,
+                  -1.0F, 1.0F);
+      save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled;
+      if (ctx->Transform.ClipPlanesEnabled) {
+         GLuint i;
+         for (i = 0; i < ctx->Const.MaxClipPlanes; i++) {
+            _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_FALSE);
+         }
+      }
+   }
+
+   if (state & META_VERTEX) {
+      /* save vertex array object state */
+      _mesa_reference_array_object(ctx, &save->ArrayObj,
+                                   ctx->Array.ArrayObj);
+      _mesa_reference_buffer_object(ctx, &save->ArrayBufferObj,
+                                    ctx->Array.ArrayBufferObj);
+      /* set some default state? */
+   }
+
+   if (state & META_VIEWPORT) {
+      save->ViewportX = ctx->Viewport.X;
+      save->ViewportY = ctx->Viewport.Y;
+      save->ViewportW = ctx->Viewport.Width;
+      save->ViewportH = ctx->Viewport.Height;
+      _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height);
+      save->DepthNear = ctx->Viewport.Near;
+      save->DepthFar = ctx->Viewport.Far;
+      _mesa_DepthRange(0.0, 1.0);
+   }
+
+   /* misc */
+   {
+      save->Lighting = ctx->Light.Enabled;
+      if (ctx->Light.Enabled)
+         _mesa_set_enable(ctx, GL_LIGHTING, GL_FALSE);
+
+      save->Fog = ctx->Fog.Enabled;
+      if (ctx->Fog.Enabled)
+         _mesa_set_enable(ctx, GL_FOG, GL_FALSE);
+   }
+}
+
+
+/**
+ * Leave meta state.  This is like a light-weight version of glPopAttrib().
+ */
+static void
+_mesa_meta_end(GLcontext *ctx)
+{
+   struct save_state *save = &ctx->Meta->Save;
+   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);
+   }
+
+   if (state & META_BLEND) {
+      if (ctx->Color.BlendEnabled != save->BlendEnabled)
+         _mesa_set_enable(ctx, GL_BLEND, save->BlendEnabled);
+      if (ctx->Color.ColorLogicOpEnabled != save->ColorLogicOpEnabled)
+         _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, save->ColorLogicOpEnabled);
+   }
+
+   if (state & META_COLOR_MASK) {
+      if (!TEST_EQ_4V(ctx->Color.ColorMask, save->ColorMask))
+         _mesa_ColorMask(save->ColorMask[0], save->ColorMask[1],
+                         save->ColorMask[2], save->ColorMask[3]);
+   }
+
+   if (state & META_DEPTH_TEST) {
+      if (ctx->Depth.Test != save->Depth.Test)
+         _mesa_set_enable(ctx, GL_DEPTH_TEST, save->Depth.Test);
+      _mesa_DepthFunc(save->Depth.Func);
+      _mesa_DepthMask(save->Depth.Mask);
+   }
+
+   if (state & META_RASTERIZATION) {
+      _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_OFFSET_FILL, save->PolygonOffset);
+      _mesa_set_enable(ctx, GL_POLYGON_SMOOTH, save->PolygonSmooth);
+      _mesa_set_enable(ctx, GL_CULL_FACE, save->PolygonCull);
+   }
+
+   if (state & META_SCISSOR) {
+      _mesa_set_enable(ctx, GL_SCISSOR_TEST, save->Scissor.Enabled);
+      _mesa_Scissor(save->Scissor.X, save->Scissor.Y,
+                    save->Scissor.Width, save->Scissor.Height);
+   }
+
+   if (state & META_SHADER) {
+      if (ctx->Extensions.ARB_vertex_program) {
+         _mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB,
+                          save->VertexProgramEnabled);
+         _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, 
+                                  save->VertexProgram);
+      }
+
+      if (ctx->Extensions.ARB_fragment_program) {
+         _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB,
+                          save->FragmentProgramEnabled);
+         _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
+                                  save->FragmentProgram);
+      }
+
+      if (ctx->Extensions.ARB_shader_objects) {
+         _mesa_UseProgramObjectARB(save->Shader);
+      }
+   }
+
+   if (state & META_STENCIL_TEST) {
+      const struct gl_stencil_attrib *stencil = &save->Stencil;
+
+      _mesa_set_enable(ctx, GL_STENCIL_TEST, stencil->Enabled);
+      _mesa_ClearStencil(stencil->Clear);
+      if (ctx->Extensions.EXT_stencil_two_side) {
+         _mesa_set_enable(ctx, GL_STENCIL_TEST_TWO_SIDE_EXT,
+                          stencil->TestTwoSide);
+         _mesa_ActiveStencilFaceEXT(stencil->ActiveFace
+                                    ? GL_BACK : GL_FRONT);
+      }
+      /* front state */
+      _mesa_StencilFuncSeparate(GL_FRONT,
+                                stencil->Function[0],
+                                stencil->Ref[0],
+                                stencil->ValueMask[0]);
+      _mesa_StencilMaskSeparate(GL_FRONT, stencil->WriteMask[0]);
+      _mesa_StencilOpSeparate(GL_FRONT, stencil->FailFunc[0],
+                              stencil->ZFailFunc[0],
+                              stencil->ZPassFunc[0]);
+      /* back state */
+      _mesa_StencilFuncSeparate(GL_BACK,
+                                stencil->Function[1],
+                                stencil->Ref[1],
+                                stencil->ValueMask[1]);
+      _mesa_StencilMaskSeparate(GL_BACK, stencil->WriteMask[1]);
+      _mesa_StencilOpSeparate(GL_BACK, stencil->FailFunc[1],
+                              stencil->ZFailFunc[1],
+                              stencil->ZPassFunc[1]);
+   }
+
+   if (state & META_TEXTURE) {
+      GLuint u, tgt;
+
+      ASSERT(ctx->Texture.CurrentUnit == 0);
+
+      /* restore texenv for unit[0] */
+      _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]);
+      }
+
+      /* 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);
+         }
+
+         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);
+         }
+      }
+
+      /* restore current unit state */
+      _mesa_ActiveTextureARB(GL_TEXTURE0 + save->ActiveUnit);
+      _mesa_ClientActiveTextureARB(GL_TEXTURE0 + save->ClientActiveUnit);
+   }
+
+   if (state & META_TRANSFORM) {
+      _mesa_MatrixMode(GL_MODELVIEW);
+      _mesa_LoadMatrixf(save->ModelviewMatrix);
+      _mesa_MatrixMode(GL_PROJECTION);
+      _mesa_LoadMatrixf(save->ProjectionMatrix);
+      _mesa_MatrixMode(save->MatrixMode);
+      save->ClipPlanesEnabled = ctx->Transform.ClipPlanesEnabled;
+      if (save->ClipPlanesEnabled) {
+         GLuint i;
+         for (i = 0; i < ctx->Const.MaxClipPlanes; i++) {
+            if (save->ClipPlanesEnabled & (1 << i)) {
+               _mesa_set_enable(ctx, GL_CLIP_PLANE0 + i, GL_TRUE);
+            }
+         }
+      }
+   }
+
+   if (state & META_VERTEX) {
+      /* restore vertex buffer object */
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, save->ArrayBufferObj->Name);
+      _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);
+   }
+
+   if (state & META_VIEWPORT) {
+      _mesa_Viewport(save->ViewportX, save->ViewportY,
+                     save->ViewportW, save->ViewportH);
+      _mesa_DepthRange(save->DepthNear, save->DepthFar);
+   }
+
+   /* misc */
+   if (save->Lighting) {
+      _mesa_set_enable(ctx, GL_LIGHTING, GL_TRUE);
+   }
+   if (save->Fog) {
+      _mesa_set_enable(ctx, GL_FOG, GL_TRUE);
+   }
+}
+
+
+/**
+ * Meta implementation of ctx->Driver.BlitFramebuffer() in terms
+ * of texture mapping and polygon rendering.
+ * Note: this function requires GL_ARB_texture_rectangle support.
+ */
+void
+_mesa_meta_blit_framebuffer(GLcontext *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;
+   const GLint srcX = MIN2(srcX0, srcX1);
+   const GLint srcY = MIN2(srcY0, srcY1);
+   const GLint srcW = abs(srcX1 - srcX0);
+   const GLint srcH = abs(srcY1 - srcY0);
+   GLboolean srcFlipX = srcX1 < srcX0;
+   GLboolean srcFlipY = srcY1 < srcY0;
+
+   ASSERT(ctx->Extensions.NV_texture_rectangle);
+
+   if (srcFlipX) {
+      GLint tmp = dstX0;
+      dstX0 = dstX1;
+      dstX1 = tmp;
+   }
+
+   if (srcFlipY) {
+      GLint tmp = dstY0;
+      dstY0 = dstY1;
+      dstY1 = tmp;
+   }
+
+   /* only scissor effects blit so save/clear all other relevant state */
+   _mesa_meta_begin(ctx, ~META_SCISSOR);
+
+   if (blit->TexObj == 0) {
+      /* one-time setup */
+
+      /* create texture object */
+      _mesa_GenTextures(1, &blit->TexObj);
+      _mesa_BindTexture(GL_TEXTURE_RECTANGLE, blit->TexObj);
+      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+   }
+   else {
+      _mesa_BindTexture(GL_TEXTURE_RECTANGLE, blit->TexObj);
+   }
+
+   _mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, filter);
+   _mesa_TexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, filter);
+
+   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_GenBuffersARB(1, &blit->VBO);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO);
+      _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(blit->verts),
+                          blit->verts, GL_STREAM_DRAW_ARB);
+
+      /* setup vertex arrays */
+      _mesa_VertexPointer(2, GL_FLOAT, 4 * sizeof(GLfloat),
+                          (void*) (0 * sizeof(GLfloat)));
+      _mesa_TexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat),
+                            (void *) (2 * sizeof(GLfloat)));
+      _mesa_EnableClientState(GL_VERTEX_ARRAY);
+      _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY);
+   }
+   else {
+      _mesa_BindVertexArray(blit->ArrayObj);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO);
+   }
+
+   /* vertex positions */
+   blit->verts[0][0] = (GLfloat) dstX0;
+   blit->verts[0][1] = (GLfloat) dstY0;
+   blit->verts[1][0] = (GLfloat) dstX1;
+   blit->verts[1][1] = (GLfloat) dstY0;
+   blit->verts[2][0] = (GLfloat) dstX1;
+   blit->verts[2][1] = (GLfloat) dstY1;
+   blit->verts[3][0] = (GLfloat) dstX0;
+   blit->verts[3][1] = (GLfloat) dstY1;
+
+   /* texcoords */
+   blit->verts[0][2] = 0.0F;
+   blit->verts[0][3] = 0.0F;
+   blit->verts[1][2] = (GLfloat) srcW;
+   blit->verts[1][3] = 0.0F;
+   blit->verts[2][2] = (GLfloat) srcW;
+   blit->verts[2][3] = (GLfloat) srcH;
+   blit->verts[3][2] = 0.0F;
+   blit->verts[3][3] = (GLfloat) srcH;
+
+   /* upload new vertex data */
+   _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
+                          sizeof(blit->verts), blit->verts);
+
+   /* copy framebuffer image to texture */
+   if (mask & GL_COLOR_BUFFER_BIT) {
+      _mesa_CopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA,
+                           srcX, srcY, srcW, srcH, 0);
+      mask &= ~GL_COLOR_BUFFER_BIT;
+   }
+
+   _mesa_Enable(GL_TEXTURE_RECTANGLE);
+
+   /* draw textured quad */
+   _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+   _mesa_Disable(GL_TEXTURE_RECTANGLE);
+
+   _mesa_meta_end(ctx);
+
+   /* XXX, TO-DO: try to handle these cases above! */
+   if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
+      _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1,
+                              dstX0, dstY0, dstX1, dstY1, mask, filter);
+   }
+
+   _mesa_Finish();
+}
+
+
+/**
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ */
+void
+_mesa_meta_clear(GLcontext *ctx, GLbitfield buffers)
+{
+   struct clear_state *clear = &ctx->Meta->Clear;
+   GLfloat z = 1.0 - 2.0 * ctx->Depth.Clear;
+   GLuint i;
+
+   /* only scissor and color mask effects clearing */
+   _mesa_meta_begin(ctx, ~(META_SCISSOR | META_COLOR_MASK));
+
+   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_GenBuffersARB(1, &clear->VBO);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO);
+      _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(clear->verts),
+                          clear->verts, GL_STREAM_DRAW_ARB);
+
+      /* setup vertex arrays */
+      _mesa_VertexPointer(3, GL_FLOAT, 7 * sizeof(GLfloat), (void *) 0);
+      _mesa_ColorPointer(4, GL_FLOAT, 7 * sizeof(GLfloat),
+                         (void *) (3 * sizeof(GLfloat)));
+      _mesa_EnableClientState(GL_VERTEX_ARRAY);
+      _mesa_EnableClientState(GL_COLOR_ARRAY);
+   }
+   else {
+      _mesa_BindVertexArray(clear->ArrayObj);
+      _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO);
+   }
+
+   /* GL_COLOR_BUFFER_BIT */
+   if (buffers & BUFFER_BITS_COLOR) {
+      /* leave colormask, glDrawBuffer state as-is */
+   }
+   else {
+      _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 & 0x7fffffff,
+                                ctx->Stencil.WriteMask[0]);
+   }
+   else {
+      assert(!ctx->Stencil.Enabled);
+   }
+
+   /* vertex positions */
+   clear->verts[0][0] = (GLfloat) ctx->DrawBuffer->_Xmin;
+   clear->verts[0][1] = (GLfloat) ctx->DrawBuffer->_Ymin;
+   clear->verts[0][2] = z;
+   clear->verts[1][0] = (GLfloat) ctx->DrawBuffer->_Xmax;
+   clear->verts[1][1] = (GLfloat) ctx->DrawBuffer->_Ymin;
+   clear->verts[1][2] = z;
+   clear->verts[2][0] = (GLfloat) ctx->DrawBuffer->_Xmax;
+   clear->verts[2][1] = (GLfloat) ctx->DrawBuffer->_Ymax;
+   clear->verts[2][2] = z;
+   clear->verts[3][0] = (GLfloat) ctx->DrawBuffer->_Xmin;
+   clear->verts[3][1] = (GLfloat) ctx->DrawBuffer->_Ymax;
+   clear->verts[3][2] = z;
+
+   /* vertex colors */
+   for (i = 0; i < 4; i++) {
+      COPY_4FV(&clear->verts[i][3], ctx->Color.ClearColor);
+   }
+
+   /* upload new vertex data */
+   _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
+                          sizeof(clear->verts), clear->verts);
+
+   /* draw quad */
+   _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+   _mesa_meta_end(ctx);
+}
+
diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
new file mode 100644
index 0000000..b63ad99
--- /dev/null
+++ b/src/mesa/drivers/common/meta.h
@@ -0,0 +1,67 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.6
+ *
+ * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef META_H
+#define META_H
+
+
+/**
+ * Flags passed to _mesa_meta_begin().
+ * XXX these flags may evolve...
+ */
+/*@{*/
+#define META_ALPHA_TEST      0x1
+#define META_BLEND           0x2  /**< includes logicop */
+#define META_COLOR_MASK      0x4
+#define META_DEPTH_TEST      0x8
+#define META_RASTERIZATION  0x10
+#define META_SCISSOR        0x20
+#define META_SHADER         0x40
+#define META_STENCIL_TEST   0x80
+#define META_TRANSFORM     0x100 /**< modelview, projection */
+#define META_TEXTURE       0x200
+#define META_VERTEX        0x400
+#define META_VIEWPORT      0x800
+#define META_ALL            ~0x0
+/*@}*/
+
+
+extern void
+_mesa_meta_init(GLcontext *ctx);
+
+extern void
+_mesa_meta_free(GLcontext *ctx);
+
+extern void
+_mesa_meta_blit_framebuffer(GLcontext *ctx,
+                            GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                            GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                            GLbitfield mask, GLenum filter);
+
+extern void
+_mesa_meta_clear(GLcontext *ctx, GLbitfield buffers);
+
+
+#endif /* META_H */
diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak
index b4b3636..d1c109c 100644
--- a/src/mesa/sources.mak
+++ b/src/mesa/sources.mak
@@ -303,7 +303,8 @@ SPARC_API =			\
 	sparc/glapi_sparc.S
 
 COMMON_DRIVER_SOURCES =			\
-	drivers/common/driverfuncs.c
+	drivers/common/driverfuncs.c	\
+	drivers/common/meta.c
 
 
 # Sources for building non-Gallium drivers




More information about the mesa-commit mailing list