gallium: new surface/context tracker (sct) module

Will be used for tracking the surfaces and textures which are bound/used by
contexts.
This commit is contained in:
Brian 2008-03-10 17:21:43 -06:00
parent 5b82d551b7
commit d5692cb349
6 changed files with 659 additions and 1 deletions

View 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)

View file

@ -0,0 +1,12 @@
TOP = ../../../..
include $(TOP)/configs/current
LIBNAME = sct
C_SOURCES = \
sct.c
include ../../Makefile.template
symlinks:

View file

@ -0,0 +1,9 @@
Import('*')
sct = env.ConvenienceLibrary(
target = 'sct',
source = [
'sct.c'
])
auxiliaries.insert(0, sct)

View file

@ -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;
}
}
}
}

View file

@ -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 */

View file

@ -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.
*/