gallium: new surface/context tracker (sct) module
authorBrian <brian.paul@tungstengraphics.com>
Mon, 10 Mar 2008 23:21:43 +0000 (17:21 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Mon, 10 Mar 2008 23:22:18 +0000 (17:22 -0600)
Will be used for tracking the surfaces and textures which are bound/used by
contexts.

configs/default
src/gallium/auxiliary/sct/Makefile [new file with mode: 0644]
src/gallium/auxiliary/sct/SConscript [new file with mode: 0644]
src/gallium/auxiliary/sct/sct.c [new file with mode: 0644]
src/gallium/auxiliary/sct/sct.h [new file with mode: 0644]
src/gallium/auxiliary/sct/usage.c [new file with mode: 0644]

index 48ddd29..f0146c5 100644 (file)
@@ -68,7 +68,7 @@ PROGRAM_DIRS = demos redbook samples glsl xdemos
 
 
 # Gallium directories and 
-GALLIUM_AUXILIARY_DIRS = draw cso_cache pipebuffer tgsi rtasm util
+GALLIUM_AUXILIARY_DIRS = draw cso_cache pipebuffer tgsi rtasm util sct
 GALLIUM_AUXILIARIES = $(foreach DIR,$(GALLIUM_AUXILIARY_DIRS),$(TOP)/src/gallium/auxiliary/$(DIR)/lib$(DIR).a)
 GALLIUM_DRIVER_DIRS = softpipe i915simple i965simple failover
 GALLIUM_DRIVERS = $(foreach DIR,$(GALLIUM_DRIVER_DIRS),$(TOP)/src/gallium/drivers/$(DIR)/lib$(DIR).a)
diff --git a/src/gallium/auxiliary/sct/Makefile b/src/gallium/auxiliary/sct/Makefile
new file mode 100644 (file)
index 0000000..516d175
--- /dev/null
@@ -0,0 +1,12 @@
+TOP = ../../../..
+include $(TOP)/configs/current
+
+LIBNAME = sct
+
+C_SOURCES = \
+       sct.c
+
+include ../../Makefile.template
+
+symlinks:
+
diff --git a/src/gallium/auxiliary/sct/SConscript b/src/gallium/auxiliary/sct/SConscript
new file mode 100644 (file)
index 0000000..76927d9
--- /dev/null
@@ -0,0 +1,9 @@
+Import('*')
+
+sct = env.ConvenienceLibrary(
+       target = 'sct',
+       source = [
+               'sct.c'
+       ])
+
+auxiliaries.insert(0, sct)
diff --git a/src/gallium/auxiliary/sct/sct.c b/src/gallium/auxiliary/sct/sct.c
new file mode 100644 (file)
index 0000000..97ee588
--- /dev/null
@@ -0,0 +1,453 @@
+/**************************************************************************
+ * 
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ * 
+ **************************************************************************/
+
+
+#include "pipe/p_util.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+#include "sct.h"
+
+
+struct texture_list
+{
+   struct pipe_texture *texture;
+   struct texture_list *next;
+};
+
+
+
+#define MAX_SURFACES  ((PIPE_MAX_COLOR_BUFS) + 1)
+
+struct sct_context
+{
+   const struct pipe_context *context;
+
+   /** surfaces the context is drawing into */
+   struct pipe_surface *surfaces[MAX_SURFACES];
+
+   /** currently bound textures */
+   struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
+
+   /** previously bound textures, used but not flushed */
+   struct texture_list *textures_used;
+
+   boolean needs_flush;
+
+   struct sct_context *next;
+};
+
+
+
+struct sct_surface
+{
+   const struct pipe_surface *surface;
+
+   /** list of contexts drawing to this surface */
+   struct sct_context_list *contexts;
+
+   struct sct_surface *next;
+};
+
+
+
+/**
+ * Find the surface_info for the given pipe_surface
+ */
+static struct sct_surface *
+find_surface_info(struct surface_context_tracker *sct,
+                  const struct pipe_surface *surface)
+{
+   struct sct_surface *si;
+   for (si = sct->surfaces; si; si = si->next)
+      if (si->surface == surface)
+         return si;
+   return NULL;
+}
+
+
+/**
+ * As above, but create new surface_info if surface is new.
+ */
+static struct sct_surface *
+find_create_surface_info(struct surface_context_tracker *sct,
+                         const struct pipe_surface *surface)
+{
+   struct sct_surface *si = find_surface_info(sct, surface);
+   if (si)
+      return si;
+
+   /* alloc new */
+   si = CALLOC_STRUCT(sct_surface);
+   if (si) {
+      si->surface = surface;
+
+      /* insert at head */
+      si->next = sct->surfaces;
+      sct->surfaces = si;
+   }
+
+   return si;
+}
+
+
+/**
+ * Find a context_info for the given context.
+ */
+static struct sct_context *
+find_context_info(struct surface_context_tracker *sct,
+                  const struct pipe_context *context)
+{
+   struct sct_context *ci;
+   for (ci = sct->contexts; ci; ci = ci->next)
+      if (ci->context == context)
+         return ci;
+   return NULL;
+}
+
+
+/**
+ * As above, but create new context_info if context is new.
+ */
+static struct sct_context *
+find_create_context_info(struct surface_context_tracker *sct,
+                         const struct pipe_context *context)
+{
+   struct sct_context *ci = find_context_info(sct, context);
+   if (ci)
+      return ci;
+
+   /* alloc new */
+   ci = CALLOC_STRUCT(sct_context);
+   if (ci) {
+      ci->context = context;
+
+      /* insert at head */
+      ci->next = sct->contexts;
+      sct->contexts = ci;
+   }
+
+   return ci;
+}
+
+
+/**
+ * Is the context already bound to the surface?
+ */
+static boolean
+find_surface_context(const struct sct_surface *si,
+                     const struct pipe_context *context)
+{
+   const struct sct_context_list *cl;
+   for (cl = si->contexts; cl; cl = cl->next) {
+      if (cl->context == context) {
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+
+/**
+ * Add a context to the list of contexts associated with a surface.
+ */
+static void
+add_context_to_surface(struct sct_surface *si,
+                       const struct pipe_context *context)
+{
+   struct sct_context_list *cl = CALLOC_STRUCT(sct_context_list);
+   if (cl) {
+      cl->context = context;
+      /* insert at head of list of contexts */
+      cl->next = si->contexts;
+      si->contexts = cl;
+   }
+}
+
+
+/**
+ * Remove a context from the list of contexts associated with a surface.
+ */
+static void
+remove_context_from_surface(struct sct_surface *si,
+                            const struct pipe_context *context)
+{
+   struct sct_context_list *prev = NULL, *curr, *next;
+
+   for (curr = si->contexts; curr; curr = next) {
+      if (curr->context == context) {
+         /* remove */
+         if (prev)
+            prev->next = curr->next;
+         else
+            si->contexts = curr->next;
+         next = curr->next;
+         FREE(curr);
+      }
+      else {
+         prev = curr;
+      }
+   }
+}
+
+
+/**
+ * Unbind context from surface.
+ */
+static void
+unbind_context_surface(struct surface_context_tracker *sct,
+                       struct pipe_context *context,
+                       struct pipe_surface *surface)
+{
+   struct sct_surface *si = find_surface_info(sct, surface);
+   if (si) {
+      remove_context_from_surface(si, context);
+   }
+}
+
+
+/**
+ * Bind context to a set of surfaces (color + Z).
+ * Like MakeCurrent().
+ */
+void
+sct_bind_surfaces(struct surface_context_tracker *sct,
+                  struct pipe_context *context,
+                  uint num_surf,
+                  struct pipe_surface **surfaces)
+{
+   struct sct_context *ci = find_create_context_info(sct, context);
+   uint i;
+
+   if (!ci) {
+      return; /* out of memory */
+   }
+
+   /* unbind currently bound surfaces */
+   for (i = 0; i < MAX_SURFACES; i++) {
+      if (ci->surfaces[i]) {
+         unbind_context_surface(sct, context, ci->surfaces[i]);
+      }
+   }
+
+   /* bind new surfaces */
+   for (i = 0; i < num_surf; i++) {
+      struct sct_surface *si = find_create_surface_info(sct, surfaces[i]);
+      if (!find_surface_context(si, context)) {
+         add_context_to_surface(si, context);
+      }
+   }
+}
+
+
+/**
+ * Return list of contexts bound to a surface.
+ */
+const struct sct_context_list *
+sct_get_surface_contexts(struct surface_context_tracker *sct,
+                         const struct pipe_surface *surface)
+{
+   const struct sct_surface *si = find_surface_info(sct, surface);
+   return si->contexts;
+}
+
+
+
+static boolean
+find_texture(const struct sct_context *ci,
+             const struct pipe_texture *texture)
+{
+   const struct texture_list *tl;
+
+   for (tl = ci->textures_used; tl; tl = tl->next) {
+      if (tl->texture == texture) {
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+
+/**
+ * Add the given texture to the context's list of used textures.
+ */
+static void
+add_texture_used(struct sct_context *ci,
+                 struct pipe_texture *texture)
+{
+   if (!find_texture(ci, texture)) {
+      /* add to list */
+      struct texture_list *tl = CALLOC_STRUCT(texture_list);
+      if (tl) {
+         pipe_texture_reference(&tl->texture, texture);
+         /* insert at head */
+         tl->next = ci->textures_used;
+         ci->textures_used = tl;
+      }
+   }
+}
+
+
+/**
+ * Bind a texture to a rendering context.
+ */
+void
+sct_bind_texture(struct surface_context_tracker *sct,
+                 struct pipe_context *context,
+                 uint unit,
+                 struct pipe_texture *tex)
+{
+   struct sct_context *ci = find_context_info(sct, context);
+
+   if (ci->textures[unit] != tex) {
+      /* put texture on the 'used' list */
+      add_texture_used(ci, tex);
+      /* bind new */
+      pipe_texture_reference(&ci->textures[unit], tex);
+   }
+}
+
+
+/**
+ * Check if the given texture has been used by the rendering context
+ * since the last call to sct_flush_textures().
+ */
+boolean
+sct_is_texture_used(struct surface_context_tracker *sct,
+                    const struct pipe_context *context,
+                    const struct pipe_texture *texture)
+{
+   const struct sct_context *ci = find_context_info(sct, context);
+   return find_texture(ci, texture);
+}
+
+
+/**
+ * To be called when the image contents of a texture are changed, such
+ * as for gl[Copy]TexSubImage().
+ * XXX this may not be needed
+ */
+void
+sct_update_texture(struct pipe_texture *tex)
+{
+
+}
+
+
+/**
+ * When a scene is flushed/rendered we can release the list of
+ * used textures.
+ */
+void
+sct_flush_textures(struct surface_context_tracker *sct,
+                   struct pipe_context *context)
+{
+   struct sct_context *ci = find_context_info(sct, context);
+   struct texture_list *tl, *next;
+   uint i;
+
+   for (tl = ci->textures_used; tl; tl = next) {
+      next = tl->next;
+      pipe_texture_release(&tl->texture);
+      FREE(tl);
+   }
+   ci->textures_used = NULL;
+
+   /* put the currently bound textures on the 'used' list */
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
+      add_texture_used(ci, ci->textures[i]);
+   }
+}
+
+
+
+void
+sct_destroy_context(struct surface_context_tracker *sct,
+                    struct pipe_context *context)
+{
+   /* XXX should we require an unbinding first? */
+   {
+      struct sct_surface *si;
+      for (si = sct->surfaces; si; si = si->next) {
+         remove_context_from_surface(si, context);
+      }
+   }
+
+   /* remove context from context_info list */
+   {
+      struct sct_context *ci, *next, *prev = NULL;
+      for (ci = sct->contexts; ci; ci = next) {
+         next = ci->next;
+         if (ci->context == context) {
+            if (prev)
+               prev->next = ci->next;
+            else
+               sct->contexts = ci->next;
+            FREE(ci);
+         }
+         else {
+            prev = ci;
+         }
+      }
+   }
+
+}
+
+
+void
+sct_destroy_surface(struct surface_context_tracker *sct,
+                    struct pipe_surface *surface)
+{
+   if (1) {
+      /* debug/sanity: no context should be bound to surface */
+      struct sct_context *ci;
+      uint i;
+      for (ci = sct->contexts; ci; ci = ci->next) {
+         for (i = 0; i < MAX_SURFACES; i++) {
+            assert(ci->surfaces[i] != surface);
+         }
+      }
+   }
+
+   /* remove surface from sct_surface list */
+   {
+      struct sct_surface *si, *next, *prev = NULL;
+      for (si = sct->surfaces; si; si = next) {
+         next = si->next;
+         if (si->surface == surface) {
+            /* unlink */
+            if (prev)
+               prev->next = si->next;
+            else
+               sct->surfaces = si->next;
+            FREE(si);
+         }
+         else {
+            prev = si;
+         }
+      }
+   }
+}
diff --git a/src/gallium/auxiliary/sct/sct.h b/src/gallium/auxiliary/sct/sct.h
new file mode 100644 (file)
index 0000000..cf7c4d3
--- /dev/null
@@ -0,0 +1,123 @@
+/**************************************************************************
+ * 
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ * 
+ **************************************************************************/
+
+/**
+ * Surface/Context Tracking
+ *
+ * For some drivers, we need to monitor the binding between contexts and
+ * surfaces/textures.
+ * This code may evolve quite a bit...
+ */
+
+
+#ifndef SCT_H
+#define SCT_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct pipe_context;
+struct pipe_surface;
+
+struct sct_context;
+struct sct_surface;
+
+
+/**
+ * Per-device info, basically
+ */
+struct surface_context_tracker
+{
+   struct sct_context *contexts;
+   struct sct_surface *surfaces;
+};
+
+
+
+/**
+ * Simple linked list of contexts
+ */
+struct sct_context_list
+{
+   const struct pipe_context *context;
+   struct sct_context_list *next;
+};
+
+
+
+extern void
+sct_bind_surfaces(struct surface_context_tracker *sct,
+                  struct pipe_context *context,
+                  uint num_surf,
+                  struct pipe_surface **surfaces);
+
+
+extern void
+sct_bind_texture(struct surface_context_tracker *sct,
+                 struct pipe_context *context,
+                 uint unit,
+                 struct pipe_texture *texture);
+
+
+extern void
+sct_update_texture(struct pipe_texture *tex);
+
+
+extern boolean
+sct_is_texture_used(struct surface_context_tracker *sct,
+                    const struct pipe_context *context,
+                    const struct pipe_texture *texture);
+
+extern void
+sct_flush_textures(struct surface_context_tracker *sct,
+                   struct pipe_context *context);
+
+
+extern const struct sct_context_list *
+sct_get_surface_contexts(struct surface_context_tracker *sct,
+                         const struct pipe_surface *surf);
+
+
+extern void
+sct_destroy_context(struct surface_context_tracker *sct,
+                    struct pipe_context *context);
+
+
+extern void
+sct_destroy_surface(struct surface_context_tracker *sct,
+                    struct pipe_surface *surface);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCT_H */
diff --git a/src/gallium/auxiliary/sct/usage.c b/src/gallium/auxiliary/sct/usage.c
new file mode 100644 (file)
index 0000000..6227f19
--- /dev/null
@@ -0,0 +1,61 @@
+/* surface / context tracking */
+
+
+/*
+
+context A:
+  render to texture T
+
+context B:
+  texture from T
+
+-----------------------
+
+flush surface:
+  which contexts are bound to the surface?
+
+-----------------------
+
+glTexSubImage():
+  which contexts need to be flushed?
+
+ */
+
+
+/*
+
+in MakeCurrent():
+
+  call sct_bind_surfaces(context, list of surfaces) to update the
+  dependencies between context and surfaces
+
+
+in SurfaceFlush(), or whatever it is in D3D:
+
+  call sct_get_surface_contexts(surface) to get a list of contexts
+  which are currently bound to the surface.
+
+
+
+in BindTexture():
+
+  call sct_bind_texture(context, texture) to indicate that the texture
+  is used in the scene.
+
+
+in glTexSubImage() or RenderToTexture():
+
+  call sct_is_texture_used(context, texture) to determine if the texture
+  has been used in the scene, but the scene's not flushed.  If TRUE is
+  returned it means the scene has to be rendered/flushed before the contents
+  of the texture can be changed.
+
+
+in psb_scene_flush/terminate():
+
+  call sct_flush_textures(context) to tell the SCT that the textures which
+  were used in the scene can be released.
+
+
+
+*/