gallium: fix lack of surface reference counting in cso_set/save/restore_framebuffer()
[mesa.git] / src / gallium / auxiliary / cso_cache / cso_context.c
index dc5987df4485451d6f5e2b4554d3577fd214e08f..b1ccfc0374a07189f09da1fe3a75b39a6db51742 100644 (file)
@@ -36,9 +36,9 @@
   */
 
 #include "pipe/p_state.h"
-#include "pipe/p_util.h"
+#include "util/u_memory.h"
 #include "pipe/p_inlines.h"
-#include "tgsi/util/tgsi_parse.h"
+#include "tgsi/tgsi_parse.h"
 
 #include "cso_cache/cso_context.h"
 #include "cso_cache/cso_cache.h"
@@ -292,7 +292,7 @@ enum pipe_error cso_set_blend(struct cso_context *ctx,
       if (!cso)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
-      cso->state = *templ;
+      memcpy(&cso->state, templ, sizeof(*templ));
       cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state);
       cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state;
       cso->context = ctx->pipe;
@@ -350,7 +350,7 @@ enum pipe_error cso_single_sampler(struct cso_context *ctx,
          if (!cso)
             return PIPE_ERROR_OUT_OF_MEMORY;
 
-         cso->state = *templ;
+         memcpy(&cso->state, templ, sizeof(*templ));
          cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state);
          cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state;
          cso->context = ctx->pipe;
@@ -508,7 +508,7 @@ enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx,
       if (!cso)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
-      cso->state = *templ;
+      memcpy(&cso->state, templ, sizeof(*templ));
       cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state);
       cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state;
       cso->context = ctx->pipe;
@@ -564,7 +564,7 @@ enum pipe_error cso_set_rasterizer(struct cso_context *ctx,
       if (!cso)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
-      cso->state = *templ;
+      memcpy(&cso->state, templ, sizeof(*templ));
       cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state);
       cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state;
       cso->context = ctx->pipe;
@@ -726,7 +726,7 @@ enum pipe_error cso_set_vertex_shader(struct cso_context *ctx,
       if (!cso)
          return PIPE_ERROR_OUT_OF_MEMORY;
 
-      cso->state = *templ;
+      memcpy(cso->state, templ, sizeof(*templ));
       cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state);
       cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state;
       cso->context = ctx->pipe;
@@ -765,12 +765,30 @@ void cso_restore_vertex_shader(struct cso_context *ctx)
 }
 
 
+/**
+ * Copy framebuffer state from src to dst with refcounting of surfaces.
+ */
+static void
+copy_framebuffer_state(struct pipe_framebuffer_state *dst,
+                       const struct pipe_framebuffer_state *src)
+{
+   uint i;
+
+   dst->width = src->width;
+   dst->height = src->height;
+   dst->num_cbufs = src->num_cbufs;
+   for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
+      pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
+   }
+   pipe_surface_reference(&dst->zsbuf, src->zsbuf);
+}
+
 
 enum pipe_error cso_set_framebuffer(struct cso_context *ctx,
                                     const struct pipe_framebuffer_state *fb)
 {
    if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) {
-      ctx->fb = *fb;
+      copy_framebuffer_state(&ctx->fb, fb);
       ctx->pipe->set_framebuffer_state(ctx->pipe, fb);
    }
    return PIPE_OK;
@@ -778,13 +796,13 @@ enum pipe_error cso_set_framebuffer(struct cso_context *ctx,
 
 void cso_save_framebuffer(struct cso_context *ctx)
 {
-   ctx->fb_saved = ctx->fb;
+   copy_framebuffer_state(&ctx->fb_saved, &ctx->fb);
 }
 
 void cso_restore_framebuffer(struct cso_context *ctx)
 {
    if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) {
-      ctx->fb = ctx->fb_saved;
+      copy_framebuffer_state(&ctx->fb, &ctx->fb_saved);
       ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb);
    }
 }