llvmpipe: support pipe_resource-based constant buffers
authorBrian Paul <brianp@vmware.com>
Mon, 10 Dec 2012 19:31:46 +0000 (12:31 -0700)
committerBrian Paul <brianp@vmware.com>
Tue, 11 Dec 2012 19:48:06 +0000 (12:48 -0700)
Before this we only supported user-based constant buffers.

First, we basically plumb pipe_constant_buffer objects through llvmpipe
rather than pipe_resource objects.

Second, update llvmpipe_set_constant_buffer() and try_update_scene_state()
so they understand both resource- and user-based constant buffers.

The problem with user constant buffers is the potential for use-after-free,
as seen in some WebGL tests.  The next patch will flip the switch for
resource-based const buffers.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/gallium/drivers/llvmpipe/lp_context.c
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_texture.c

index e59ae237efd95bb92bc119876d5d8b2639c01c8a..eb454b1c41f946d7b2a04583ab673ca87d85e946 100644 (file)
@@ -83,7 +83,7 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
 
    for (i = 0; i < Elements(llvmpipe->constants); i++) {
       for (j = 0; j < Elements(llvmpipe->constants[i]); j++) {
-         pipe_resource_reference(&llvmpipe->constants[i][j], NULL);
+         pipe_resource_reference(&llvmpipe->constants[i][j].buffer, NULL);
       }
    }
 
index 5afa4360aae43438901a018ad361c413c37a1bd3..b11a3d838e317003a102c752a363525196a7f70c 100644 (file)
@@ -72,7 +72,7 @@ struct llvmpipe_context {
    struct pipe_blend_color blend_color;
    struct pipe_stencil_ref stencil_ref;
    struct pipe_clip_state clip;
-   struct pipe_resource *constants[PIPE_SHADER_TYPES][LP_MAX_TGSI_CONST_BUFFERS];
+   struct pipe_constant_buffer constants[PIPE_SHADER_TYPES][LP_MAX_TGSI_CONST_BUFFERS];
    struct pipe_framebuffer_state framebuffer;
    struct pipe_poly_stipple poly_stipple;
    struct pipe_scissor_state scissor;
index 7d40d8cf6617e3988ed2ddbafbc3e9aa0bee3d79..5aba7a2534298994624b93379868de2c9e1f205e 100644 (file)
@@ -554,7 +554,7 @@ lp_setup_set_fs_variant( struct lp_setup_context *setup,
 void
 lp_setup_set_fs_constants(struct lp_setup_context *setup,
                           unsigned num,
-                          struct pipe_resource **buffers)
+                          struct pipe_constant_buffer *buffers)
 {
    unsigned i;
 
@@ -563,11 +563,12 @@ lp_setup_set_fs_constants(struct lp_setup_context *setup,
    assert(num <= Elements(setup->constants));
 
    for (i = 0; i < num; ++i) {
-      if (setup->constants[i].current != buffers[i]) {
-         pipe_resource_reference(&setup->constants[i].current, buffers[i]);
-         setup->dirty |= LP_SETUP_NEW_CONSTANTS;
-      }
+      util_copy_constant_buffer(&setup->constants[i].current, &buffers[i]);
+   }
+   for (; i < Elements(setup->constants); i++) {
+      util_copy_constant_buffer(&setup->constants[i].current, NULL);
    }
+   setup->dirty |= LP_SETUP_NEW_CONSTANTS;
 }
 
 
@@ -873,11 +874,21 @@ try_update_scene_state( struct lp_setup_context *setup )
 
    if (setup->dirty & LP_SETUP_NEW_CONSTANTS) {
       for (i = 0; i < Elements(setup->constants); ++i) {
-         struct pipe_resource *buffer = setup->constants[i].current;
+         struct pipe_resource *buffer = setup->constants[i].current.buffer;
+         const unsigned current_size = setup->constants[i].current.buffer_size;
+         const ubyte *current_data = NULL;
 
          if (buffer) {
-            unsigned current_size = buffer->width0;
-            const void *current_data = llvmpipe_resource_data(buffer);
+            /* resource buffer */
+            current_data = (ubyte *) llvmpipe_resource_data(buffer);
+         }
+         else if (setup->constants[i].current.user_buffer) {
+            /* user-space buffer */
+            current_data = (ubyte *) setup->constants[i].current.user_buffer;
+         }
+
+         if (current_data) {
+            current_data += setup->constants[i].current.buffer_offset;
 
             /* TODO: copy only the actually used constants? */
 
@@ -1054,7 +1065,7 @@ lp_setup_destroy( struct lp_setup_context *setup )
    }
 
    for (i = 0; i < Elements(setup->constants); i++) {
-      pipe_resource_reference(&setup->constants[i].current, NULL);
+      pipe_resource_reference(&setup->constants[i].current.buffer, NULL);
    }
 
    /* free the scenes in the 'empty' queue */
index 55fbd9be8b829505cddae60f786f57c2adc9b7aa..55b710dd2b4fd421aa05a60f66d54a82168c6103 100644 (file)
@@ -101,8 +101,7 @@ lp_setup_set_fs_variant( struct lp_setup_context *setup,
 void
 lp_setup_set_fs_constants(struct lp_setup_context *setup,
                           unsigned num,
-                          struct pipe_resource **buffers);
-
+                          struct pipe_constant_buffer *buffers);
 
 void
 lp_setup_set_alpha_ref_value( struct lp_setup_context *setup,
index 60809db50a2fa2432db38bc5eb66364a39271819..4d20dd3846131dfa4a615a9c5341155b06917ec7 100644 (file)
@@ -128,7 +128,7 @@ struct lp_setup_context
 
    /** fragment shader constants */
    struct {
-      struct pipe_resource *current;
+      struct pipe_constant_buffer current;
       unsigned stored_size;
       const void *stored_data;
    } constants[LP_MAX_TGSI_CONST_BUFFERS];
index dced5d25a7fc5583241437745af2270dd1b25365..bf59a43f49a321d8f5ef1498bc93787075d09a28 100644 (file)
@@ -2408,32 +2408,32 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
    struct pipe_resource *constants = cb ? cb->buffer : NULL;
-   unsigned size;
-   const void *data;
-
-   if (cb && cb->user_buffer) {
-      constants = llvmpipe_user_buffer_create(pipe->screen,
-                                              (void *) cb->user_buffer,
-                                              cb->buffer_size,
-                                              PIPE_BIND_CONSTANT_BUFFER);
-   }
-
-   size = constants ? constants->width0 : 0;
-   data = constants ? llvmpipe_resource_data(constants) : NULL;
 
    assert(shader < PIPE_SHADER_TYPES);
    assert(index < Elements(llvmpipe->constants[shader]));
 
-   if(llvmpipe->constants[shader][index] == constants)
-      return;
+   /* note: reference counting */
+   util_copy_constant_buffer(&llvmpipe->constants[shader][index], cb);
 
-   draw_flush(llvmpipe->draw);
+   if (shader == PIPE_SHADER_VERTEX ||
+       shader == PIPE_SHADER_GEOMETRY) {
+      /* Pass the constants to the 'draw' module */
+      const unsigned size = cb ? cb->buffer_size : 0;
+      const ubyte *data;
 
-   /* note: reference counting */
-   pipe_resource_reference(&llvmpipe->constants[shader][index], constants);
+      if (constants) {
+         data = (ubyte *) llvmpipe_resource_data(constants);
+      }
+      else if (cb && cb->user_buffer) {
+         data = (ubyte *) cb->user_buffer;
+      }
+      else {
+         data = NULL;
+      }
+
+      if (data)
+         data += cb->buffer_offset;
 
-   if(shader == PIPE_SHADER_VERTEX ||
-      shader == PIPE_SHADER_GEOMETRY) {
       draw_set_mapped_constant_buffer(llvmpipe->draw, shader,
                                       index, data, size);
    }
index f4d2cb6c5d0ac50fdee240455b8409388edb15e5..31ea7dca50e43fa8ae4ed38687c30605c8614f27 100644 (file)
@@ -669,8 +669,12 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
       }
    }
 
-   if (resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][0])
+   /* Check if we're mapping the current constant buffer */
+   if ((usage & PIPE_TRANSFER_WRITE) &&
+       resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][0].buffer) {
+      /* constants may have changed */
       llvmpipe->dirty |= LP_NEW_CONSTANTS;
+   }
 
    lpt = CALLOC_STRUCT(llvmpipe_transfer);
    if (!lpt)