Use program serial numbers to avoid re-generating fragment programs for glDrawPixels.
authorBrian <brian.paul@tungstengraphics.com>
Tue, 30 Oct 2007 22:13:37 +0000 (16:13 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Tue, 30 Oct 2007 22:13:37 +0000 (16:13 -0600)
src/mesa/state_tracker/st_atom_pixeltransfer.c
src/mesa/state_tracker/st_cb_drawpixels.c
src/mesa/state_tracker/st_cb_program.c
src/mesa/state_tracker/st_context.c
src/mesa/state_tracker/st_context.h

index b190c39343ad816e250c0860d32cfc1f353a41b9..8cf340e6850b66afdf19a8c8c03bff841021e2bc 100644 (file)
@@ -42,6 +42,7 @@
 #include "shader/prog_print.h"
 
 #include "st_context.h"
+#include "st_program.h"
 
 
 
@@ -79,8 +80,6 @@ is_identity(const GLfloat m[16])
 static void
 make_state_key(GLcontext *ctx,  struct state_key *key)
 {
-   /*GLuint i, j;*/
-       
    memset(key, 0, sizeof(*key));
 
    if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 ||
@@ -189,6 +188,8 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
       inst[ic].SrcReg[0].Index = FRAG_RESULT_COLR;
       ic++;
 
+      /* XXX reimplement in terms of MUL/MAD (see t_vp_build.c) */
+
       /* DP4 result.color.x, tmp0, matrow0; */
       _mesa_init_instructions(inst + ic, 1);
       inst[ic].Opcode = OPCODE_DP4;
@@ -268,6 +269,9 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
 
 
 
+/**
+ * Update st->pixel_xfer.program in response to new pixel-transfer state.
+ */
 static void
 update_pixel_transfer(struct st_context *st)
 {
@@ -277,14 +281,14 @@ update_pixel_transfer(struct st_context *st)
    make_state_key(st->ctx, &key);
 
    fp = (struct gl_fragment_program *)
-      _mesa_search_program_cache(st->pixel_transfer_cache, &key, sizeof(key));
+      _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key));
    if (!fp) {
       fp = get_pixel_transfer_program(st->ctx, &key);
-      _mesa_program_cache_insert(st->ctx, st->pixel_transfer_cache,
+      _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache,
                                  &key, sizeof(key), &fp->Base);
    }
 
-   st->pixel_transfer_program = fp;
+   st->pixel_xfer.program = (struct st_fragment_program *) fp;
 }
 
 
index 3359338385b8a5e8420068ba184d9d9e678083ed..c74c8fa641c85e30b5364e1fab48a91581a09a3e 100644 (file)
@@ -182,30 +182,48 @@ make_drawpix_fragment_shader(struct st_context *st)
 {
    GLcontext *ctx = st->ctx;
    struct st_fragment_program *stfp;
-   struct gl_program *p;
 
-   /*
-    * XXX Use st_program's serial numbers to determine when the
-    * user-provided program and pixel-transfer program to avoid
-    * needless combining/translation here.
-    */
+   if (st->pixel_xfer.program->serialNo == st->pixel_xfer.xfer_prog_sn
+       && st->fp->serialNo == st->pixel_xfer.user_prog_sn) {
+      /* the pixel tranfer program has not changed and the user-defined
+       * shader has not changed, so re-use the combined program.
+       */
+      stfp = st->pixel_xfer.combined_prog;
+   }
+   else {
+      /* Concatenate the pixel transfer program with the current user-
+       * defined shader.
+       */
+      stfp = (struct st_fragment_program *)
+         _mesa_combine_programs(ctx,
+                                &st->pixel_xfer.program->Base.Base,
+                                &st->fp->Base.Base);
 
-   p = _mesa_combine_programs(ctx,
-                              &st->pixel_transfer_program->Base,
-                              &ctx->FragmentProgram._Current->Base);
 #if 0
-   _mesa_print_program(p);
-   printf("InputsRead: 0x%x\n", p->InputsRead);
-   printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
-   _mesa_print_parameter_list(p->Parameters);
+      {
+         struct gl_program *p = &stfp->Base.Base;
+         _mesa_print_program(p);
+         printf("InputsRead: 0x%x\n", p->InputsRead);
+         printf("OutputsWritten: 0x%x\n", p->OutputsWritten);
+         _mesa_print_parameter_list(p->Parameters);
+      }
 #endif
 
-   stfp = (struct st_fragment_program *) p;
-   st_translate_fragment_program(st, stfp, NULL,
-                                 stfp->tokens, ST_MAX_SHADER_TOKENS);
+      /* translate to TGSI tokens */
+      st_translate_fragment_program(st, stfp, NULL,
+                                    stfp->tokens, ST_MAX_SHADER_TOKENS);
 
+      /* save new program, update serial numbers */
+      st->pixel_xfer.xfer_prog_sn = st->pixel_xfer.program->serialNo;
+      st->pixel_xfer.user_prog_sn = st->fp->serialNo;
+      st->pixel_xfer.combined_prog_sn = stfp->serialNo;
+      st->pixel_xfer.combined_prog = stfp;
+   }
 
-   st_upload_constants( st, p->Parameters, PIPE_SHADER_FRAGMENT );
+   /* Ideally we'd have updated the pipe constants during the normal
+    * st/atom mechanism.  But we can't since this is specific to glDrawPixels.
+    */
+   st_upload_constants(st, stfp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT);
 
    return stfp;
 }
index a330c1c92276c81e2c4458869fbfb8248d50ce40..aed6b1ee97d1aa6fa3fab527ed5f67b7960bf20f 100644 (file)
@@ -44,6 +44,8 @@
 #include "st_atom_shader.h"
 
 
+static GLuint SerialNo = 1;
+
 
 /**
  * Called via ctx->Driver.BindProgram() to bind an ARB vertex or
@@ -91,7 +93,7 @@ static struct gl_program *st_new_program( GLcontext *ctx,
    case GL_VERTEX_PROGRAM_ARB: {
       struct st_vertex_program *prog = CALLOC_STRUCT(st_vertex_program);
 
-      prog->serialNo = 1;
+      prog->serialNo = SerialNo++;
 
       return _mesa_init_vertex_program( ctx, 
                                        &prog->Base,
@@ -103,7 +105,7 @@ static struct gl_program *st_new_program( GLcontext *ctx,
    case GL_FRAGMENT_PROGRAM_NV: {
       struct st_fragment_program *prog = CALLOC_STRUCT(st_fragment_program);
 
-      prog->serialNo = 1;
+      prog->serialNo = SerialNo++;
 
       return _mesa_init_fragment_program( ctx, 
                                          &prog->Base,
index e872e8b12c5f019d27842084ead9e54cade3646e..c7398233d8a28b1e7d1485bd48fb3bfc5cd1552a 100644 (file)
@@ -92,7 +92,7 @@ struct st_context *st_create_context( GLcontext *ctx,
 
    st->haveFramebufferRegions = GL_TRUE;
 
-   st->pixel_transfer_cache = _mesa_new_program_cache();
+   st->pixel_xfer.cache = _mesa_new_program_cache();
 
 #if 0
    st_init_cb_clear( st );
@@ -126,7 +126,7 @@ void st_destroy_context( struct st_context *st )
 #endif
    cso_cache_delete( st->cache );
 
-   _mesa_delete_program_cache(st->ctx, st->pixel_transfer_cache);
+   _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache);
 
    st->pipe->destroy( st->pipe );
    FREE( st );
index 4de70a3b2ea0f4e0258bdff03aec0f9f24c8e8c3..8bbfb0d6fecd5aa7dc09139f415274e3cd5c1578 100644 (file)
@@ -133,8 +133,14 @@ struct st_context
    struct st_vertex_program *vp;    /**< Currently bound vertex program */
    struct st_fragment_program *fp;  /**< Currently bound fragment program */
 
-   struct gl_fragment_program *pixel_transfer_program;
-   struct gl_program_cache *pixel_transfer_cache;
+   struct {
+      struct gl_program_cache *cache;
+      struct st_fragment_program *program;  /**< cur pixel transfer prog */
+      GLuint xfer_prog_sn;  /**< pixel xfer program serial no. */
+      GLuint user_prog_sn;  /**< user fragment program serial no. */
+      struct st_fragment_program *combined_prog;
+      GLuint combined_prog_sn;
+   } pixel_xfer;
 
    /**
     * Buffer object which stores the ctx->Current.Attrib[] values.