st-api: Rework how drawables are invalidated v3.

The api and the state tracker manager code as well as the state tracker code
assumed that only a single context could be bound to a drawable. That is not
a valid assumption, since multiple contexts can bind to the same drawable.

Fix this by making it the state tracker's responsibility to update all
contexts binding to a drawable

Note that the state trackers themselves don't use atomic stamps on
frame-buffers. Multiple context rendering to the same drawable should
be protected by the application.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
Thomas Hellstrom
2011-06-29 09:00:23 +02:00
parent 1a7e17e44a
commit ac8fdbc1c7
14 changed files with 123 additions and 122 deletions

View File

@@ -252,6 +252,12 @@ struct st_context_attribs
*/
struct st_framebuffer_iface
{
/**
* Atomic stamp which changes when framebuffers need to be updated.
*/
int32_t stamp;
/**
* Available for the state tracker manager to use.
*/
@@ -314,25 +320,6 @@ struct st_context_iface
*/
void (*destroy)(struct st_context_iface *stctxi);
/**
* Invalidate the current textures that was taken from a framebuffer.
*
* The state tracker manager calls this function to let the rendering
* context know that it should update the textures it got from
* st_framebuffer_iface::validate. It should do so at the latest time possible.
* Possible right before sending triangles to the pipe context.
*
* For certain platforms this function might be called from a thread other
* than the thread that the context is currently bound in, and must
* therefore be thread safe. But it is the state tracker manager's
* responsibility to make sure that the framebuffer is bound to the context
* and the API context is current for the duration of this call.
*
* Thus reducing the sync primitive needed to a single atomic flag.
*/
void (*notify_invalid_framebuffer)(struct st_context_iface *stctxi,
struct st_framebuffer_iface *stfbi);
/**
* Flush all drawing from context to the pipe also flushes the pipe.
*/

View File

@@ -136,6 +136,7 @@ dri_create_buffer(__DRIscreen * sPriv,
drawable->sPriv = sPriv;
drawable->dPriv = dPriv;
dPriv->driverPrivate = (void *)drawable;
p_atomic_set(&drawable->base.stamp, 1);
return GL_TRUE;
fail:

View File

@@ -52,13 +52,11 @@ static void
dri2_invalidate_drawable(__DRIdrawable *dPriv)
{
struct dri_drawable *drawable = dri_drawable(dPriv);
struct dri_context *ctx = drawable->context;
dri2InvalidateDrawable(dPriv);
drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
if (ctx)
ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base);
p_atomic_inc(&drawable->base.stamp);
}
static const __DRI2flushExtension dri2FlushExtension = {

View File

@@ -103,14 +103,11 @@ drisw_present_texture(__DRIdrawable *dPriv,
static INLINE void
drisw_invalidate_drawable(__DRIdrawable *dPriv)
{
struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv);
struct dri_drawable *drawable = dri_drawable(dPriv);
drawable->texture_stamp = dPriv->lastStamp - 1;
/* check if swapping currently bound buffer */
if (ctx && ctx->dPriv == dPriv)
ctx->st->notify_invalid_framebuffer(ctx->st, &drawable->base);
p_atomic_inc(&drawable->base.stamp);
}
static INLINE void

View File

@@ -31,6 +31,7 @@
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_string.h"
#include "util/u_atomic.h"
#include "egl_g3d.h"
#include "egl_g3d_api.h"
@@ -45,15 +46,9 @@ egl_g3d_invalid_surface(struct native_display *ndpy,
{
/* XXX not thread safe? */
struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data);
struct egl_g3d_context *gctx;
/*
* Some functions such as egl_g3d_copy_buffers create a temporary native
* surface. There is no gsurf associated with it.
*/
gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL;
if (gctx)
gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi);
if (gsurf && gsurf->stfbi)
p_atomic_inc(&gsurf->stfbi->stamp);
}
static struct pipe_screen *

View File

@@ -504,19 +504,12 @@ egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
(gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
if (ok) {
if (gdraw) {
gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
gdraw->stfbi);
if (gdraw->base.Type == EGL_WINDOW_BIT) {
gctx->base.WindowRenderBuffer =
(gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
}
}
if (gread && gread != gdraw) {
gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
gread->stfbi);
}
}
}
else if (old_gctx) {

View File

@@ -292,6 +292,8 @@ egl_g3d_create_st_framebuffer(_EGLSurface *surf)
return NULL;
stfbi->visual = &gsurf->stvis;
p_atomic_set(&stfbi->stamp, 1);
if (gsurf->base.Type != EGL_PBUFFER_BIT) {
stfbi->flush_front = egl_g3d_st_framebuffer_flush_front;
stfbi->validate = egl_g3d_st_framebuffer_validate;

View File

@@ -65,6 +65,8 @@ struct st_framebuffer {
enum st_attachment_type strb_att;
void *privateData;
int32_t stamp;
int32_t iface_stamp;
};
enum vg_object_type {
@@ -105,7 +107,6 @@ struct vg_context
VGErrorCode _error;
struct st_framebuffer *draw_buffer;
int32_t draw_buffer_invalid;
struct cso_hash *owned_objects[VG_OBJECT_LAST];
@@ -129,6 +130,8 @@ struct vg_context
struct vg_paint *default_paint;
struct blit_state *blit;
int32_t draw_stamp;
};

View File

@@ -106,35 +106,38 @@ vg_manager_validate_framebuffer(struct vg_context *ctx)
{
struct st_framebuffer *stfb = ctx->draw_buffer;
struct pipe_resource *pt;
int32_t new_stamp;
/* no binding surface */
if (!stfb)
return;
if (!p_atomic_read(&ctx->draw_buffer_invalid))
return;
new_stamp = p_atomic_read(&stfb->iface->stamp);
if (stfb->iface_stamp != new_stamp) {
do {
/* validate the fb */
if (!stfb->iface->validate(stfb->iface, &stfb->strb_att,
1, &pt) || !pt)
return;
/* validate the fb */
if (!stfb->iface->validate(stfb->iface, &stfb->strb_att, 1, &pt) || !pt)
return;
stfb->iface_stamp = new_stamp;
new_stamp = p_atomic_read(&stfb->iface->stamp);
p_atomic_set(&ctx->draw_buffer_invalid, FALSE);
} while (stfb->iface_stamp != new_stamp);
if (vg_context_update_color_rb(ctx, pt) ||
stfb->width != pt->width0 ||
stfb->height != pt->height0)
if (vg_context_update_color_rb(ctx, pt) ||
stfb->width != pt->width0 ||
stfb->height != pt->height0)
++stfb->stamp;
stfb->width = pt->width0;
stfb->height = pt->height0;
}
if (ctx->draw_stamp != stfb->stamp) {
ctx->state.dirty |= FRAMEBUFFER_DIRTY;
stfb->width = pt->width0;
stfb->height = pt->height0;
}
static void
vg_context_notify_invalid_framebuffer(struct st_context_iface *stctxi,
struct st_framebuffer_iface *stfbi)
{
struct vg_context *ctx = (struct vg_context *) stctxi;
p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
ctx->draw_stamp = stfb->stamp;
}
}
static void
@@ -187,8 +190,6 @@ vg_api_create_context(struct st_api *stapi, struct st_manager *smapi,
ctx->iface.destroy = vg_context_destroy;
ctx->iface.notify_invalid_framebuffer =
vg_context_notify_invalid_framebuffer;
ctx->iface.flush = vg_context_flush;
ctx->iface.teximage = NULL;
@@ -266,8 +267,6 @@ vg_context_bind_framebuffers(struct st_context_iface *stctxi,
if (stdrawi != streadi)
return FALSE;
p_atomic_set(&ctx->draw_buffer_invalid, TRUE);
strb_att = (stdrawi) ? choose_attachment(stdrawi) : ST_ATTACHMENT_INVALID;
if (ctx->draw_buffer) {
@@ -313,11 +312,14 @@ vg_context_bind_framebuffers(struct st_context_iface *stctxi,
stfb->width = 0;
stfb->height = 0;
stfb->strb_att = strb_att;
stfb->stamp = 1;
stfb->iface_stamp = p_atomic_read(&stdrawi->stamp) - 1;
ctx->draw_buffer = stfb;
}
ctx->draw_buffer->iface = stdrawi;
ctx->draw_stamp = ctx->draw_buffer->stamp - 1;
return TRUE;
}

View File

@@ -31,6 +31,7 @@
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "util/u_memory.h"
#include "util/u_atomic.h"
#include "state_tracker/st_api.h"
#include "stw_icd.h"
@@ -361,10 +362,7 @@ stw_flush_current_locked( struct stw_framebuffer *fb )
void
stw_notify_current_locked( struct stw_framebuffer *fb )
{
struct stw_context *ctx = stw_current_context();
if (ctx && ctx->current_framebuffer == fb)
ctx->st->notify_invalid_framebuffer(ctx->st, fb->stfb);
p_atomic_inc(&fb->stfb->stamp);
}
/**

View File

@@ -27,6 +27,7 @@
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/u_atomic.h"
#include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
#include "stw_st.h"
@@ -196,6 +197,7 @@ stw_st_create_framebuffer(struct stw_framebuffer *fb)
stwfb->stvis = fb->pfi->stvis;
stwfb->base.visual = &stwfb->stvis;
p_atomic_set(&stwfb->base.stamp, 1);
stwfb->base.flush_front = stw_st_framebuffer_flush_front;
stwfb->base.validate = stw_st_framebuffer_validate;

View File

@@ -56,13 +56,20 @@ static void st_viewport(struct gl_context * ctx, GLint x, GLint y,
if (!st->invalidate_on_gl_viewport)
return;
/*
* Normally we'd want the state tracker manager to mark the drawables
* invalid only when needed. This will force the state tracker manager
* to revalidate the drawable, rather than just update the context with
* the latest cached drawable info.
*/
stdraw = st_ws_framebuffer(st->ctx->DrawBuffer);
stread = st_ws_framebuffer(st->ctx->ReadBuffer);
if (stdraw)
p_atomic_set(&stdraw->revalidate, TRUE);
if (stread && stread != stdraw)
p_atomic_set(&stread->revalidate, TRUE);
if (stdraw && stdraw->iface)
stdraw->iface_stamp = p_atomic_read(&stdraw->iface->stamp) - 1;
if (stread && stread != stdraw && stread->iface)
stread->iface_stamp = p_atomic_read(&stread->iface->stamp) - 1;
}
void st_init_viewport_functions(struct dd_function_table *functions)

View File

@@ -204,6 +204,9 @@ struct st_context
/* Active render condition. */
struct pipe_query *render_condition;
unsigned condition_mode;
int32_t draw_stamp;
int32_t read_stamp;
};
@@ -227,7 +230,8 @@ struct st_framebuffer
struct st_framebuffer_iface *iface;
enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
unsigned num_statts;
int32_t revalidate;
int32_t stamp;
int32_t iface_stamp;
};

View File

@@ -139,23 +139,64 @@ buffer_index_to_attachment(gl_buffer_index index)
}
/**
* Validate a framebuffer to make sure up-to-date pipe_textures are used.
* Make sure a context picks up the latest cached state of the
* drawables it binds to.
*/
static void
st_framebuffer_validate(struct st_framebuffer *stfb, struct st_context *st)
st_context_validate(struct st_context *st,
struct st_framebuffer *stdraw,
struct st_framebuffer *stread)
{
if (stdraw && stdraw->stamp != st->draw_stamp) {
st->dirty.st |= ST_NEW_FRAMEBUFFER;
_mesa_resize_framebuffer(st->ctx, &stdraw->Base,
stdraw->Base.Width,
stdraw->Base.Height);
st->draw_stamp = stdraw->stamp;
}
if (stread && stread->stamp != st->read_stamp) {
if (stread != stdraw) {
st->dirty.st |= ST_NEW_FRAMEBUFFER;
_mesa_resize_framebuffer(st->ctx, &stread->Base,
stread->Base.Width,
stread->Base.Height);
}
st->read_stamp = stread->stamp;
}
}
/**
* Validate a framebuffer to make sure up-to-date pipe_textures are used.
* The context we need to pass in is s dummy context needed only to be
* able to get a pipe context to create pipe surfaces, and to have a
* context to call _mesa_resize_framebuffer():
* (That should probably be rethought, since those surfaces become
* drawable state, not context state, and can be freed by another pipe
* context).
*/
static void
st_framebuffer_validate(struct st_framebuffer *stfb,
struct st_context *st)
{
struct pipe_context *pipe = st->pipe;
struct pipe_resource *textures[ST_ATTACHMENT_COUNT];
uint width, height;
unsigned i;
boolean changed = FALSE;
int32_t new_stamp = p_atomic_read(&stfb->iface->stamp);
if (!p_atomic_read(&stfb->revalidate))
if (stfb->iface_stamp == new_stamp)
return;
/* validate the fb */
if (!stfb->iface->validate(stfb->iface, stfb->statts, stfb->num_statts, textures))
return;
do {
if (!stfb->iface->validate(stfb->iface, stfb->statts,
stfb->num_statts, textures))
return;
stfb->iface_stamp = new_stamp;
new_stamp = p_atomic_read(&stfb->iface->stamp);
} while(stfb->iface_stamp != new_stamp);
width = stfb->Base.Width;
height = stfb->Base.Height;
@@ -184,7 +225,7 @@ st_framebuffer_validate(struct st_framebuffer *stfb, struct st_context *st)
memset(&surf_tmpl, 0, sizeof(surf_tmpl));
u_surface_default_template(&surf_tmpl, textures[i],
PIPE_BIND_RENDER_TARGET);
ps = pipe->create_surface(pipe, textures[i], &surf_tmpl);
ps = st->pipe->create_surface(st->pipe, textures[i], &surf_tmpl);
if (ps) {
pipe_surface_reference(&strb->surface, ps);
pipe_resource_reference(&strb->texture, ps->texture);
@@ -204,14 +245,9 @@ st_framebuffer_validate(struct st_framebuffer *stfb, struct st_context *st)
}
if (changed) {
st->dirty.st |= ST_NEW_FRAMEBUFFER;
++stfb->stamp;
_mesa_resize_framebuffer(st->ctx, &stfb->Base, width, height);
assert(stfb->Base.Width == width);
assert(stfb->Base.Height == height);
}
p_atomic_set(&stfb->revalidate, FALSE);
}
/**
@@ -236,8 +272,7 @@ st_framebuffer_update_attachments(struct st_framebuffer *stfb)
st_visual_have_buffers(stfb->iface->visual, 1 << statt))
stfb->statts[stfb->num_statts++] = statt;
}
p_atomic_set(&stfb->revalidate, TRUE);
stfb->stamp++;
}
/**
@@ -443,6 +478,7 @@ st_framebuffer_create(struct st_framebuffer_iface *stfbi)
&stfb->Base._ColorReadBufferIndex);
stfb->iface = stfbi;
stfb->iface_stamp = p_atomic_read(&stfbi->stamp) - 1;
/* add the color buffer */
idx = stfb->Base._ColorDrawBufferIndexes[0];
@@ -454,6 +490,7 @@ st_framebuffer_create(struct st_framebuffer_iface *stfbi)
st_framebuffer_add_renderbuffer(stfb, BUFFER_DEPTH);
st_framebuffer_add_renderbuffer(stfb, BUFFER_ACCUM);
stfb->stamp = 0;
st_framebuffer_update_attachments(stfb);
stfb->Base.Initialized = GL_TRUE;
@@ -472,31 +509,6 @@ st_framebuffer_reference(struct st_framebuffer **ptr,
_mesa_reference_framebuffer((struct gl_framebuffer **) ptr, fb);
}
static void
st_context_notify_invalid_framebuffer(struct st_context_iface *stctxi,
struct st_framebuffer_iface *stfbi)
{
struct st_context *st = (struct st_context *) stctxi;
struct st_framebuffer *stfb;
/* either draw or read winsys fb */
stfb = st_ws_framebuffer(st->ctx->WinSysDrawBuffer);
if (!stfb || stfb->iface != stfbi)
stfb = st_ws_framebuffer(st->ctx->WinSysReadBuffer);
if (stfb && stfb->iface == stfbi) {
p_atomic_set(&stfb->revalidate, TRUE);
}
else {
/* This function is probably getting called when we've detected a
* change in a window's size but the currently bound context is
* not bound to that window.
* If the st_framebuffer_iface structure had a pointer to the
* corresponding st_framebuffer we'd be able to handle this.
*/
}
}
static void
st_context_flush(struct st_context_iface *stctxi, unsigned flags,
struct pipe_fence_handle **fence)
@@ -696,8 +708,6 @@ st_api_create_context(struct st_api *stapi, struct st_manager *smapi,
smapi->get_param(smapi, ST_MANAGER_BROKEN_INVALIDATE);
st->iface.destroy = st_context_destroy;
st->iface.notify_invalid_framebuffer =
st_context_notify_invalid_framebuffer;
st->iface.flush = st_context_flush;
st->iface.teximage = st_context_teximage;
st->iface.copy = st_context_copy;
@@ -762,10 +772,6 @@ st_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
}
if (stdraw && stread) {
if (stctxi != st_api_get_current(stapi)) {
p_atomic_set(&stdraw->revalidate, TRUE);
p_atomic_set(&stread->revalidate, TRUE);
}
st_framebuffer_validate(stdraw, st);
if (stread != stdraw)
st_framebuffer_validate(stread, st);
@@ -781,6 +787,10 @@ st_api_make_current(struct st_api *stapi, struct st_context_iface *stctxi,
}
ret = _mesa_make_current(st->ctx, &stdraw->Base, &stread->Base);
st->draw_stamp = stdraw->stamp - 1;
st->read_stamp = stread->stamp - 1;
st_context_validate(st, stdraw, stread);
}
else {
struct gl_framebuffer *incomplete = _mesa_get_incomplete_framebuffer();
@@ -872,6 +882,8 @@ st_manager_validate_framebuffers(struct st_context *st)
st_framebuffer_validate(stdraw, st);
if (stread && stread != stdraw)
st_framebuffer_validate(stread, st);
st_context_validate(st, stdraw, stread);
}
/**