*/
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.
*/
*/
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.
*/
drawable->sPriv = sPriv;
drawable->dPriv = dPriv;
dPriv->driverPrivate = (void *)drawable;
+ p_atomic_set(&drawable->base.stamp, 1);
return GL_TRUE;
fail:
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 = {
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
#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"
{
/* 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 *
(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) {
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;
enum st_attachment_type strb_att;
void *privateData;
+ int32_t stamp;
+ int32_t iface_stamp;
};
enum vg_object_type {
VGErrorCode _error;
struct st_framebuffer *draw_buffer;
- int32_t draw_buffer_invalid;
struct cso_hash *owned_objects[VG_OBJECT_LAST];
struct vg_paint *default_paint;
struct blit_state *blit;
+
+ int32_t draw_stamp;
};
{
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)
- ctx->state.dirty |= FRAMEBUFFER_DIRTY;
+ 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;
-}
+ 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);
+ if (ctx->draw_stamp != stfb->stamp) {
+ ctx->state.dirty |= FRAMEBUFFER_DIRTY;
+ ctx->draw_stamp = stfb->stamp;
+ }
}
static void
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;
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) {
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;
}
#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"
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);
}
/**
#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"
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;
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)
/* Active render condition. */
struct pipe_query *render_condition;
unsigned condition_mode;
+
+ int32_t draw_stamp;
+ int32_t read_stamp;
};
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;
};
return statt;
}
+/**
+ * Make sure a context picks up the latest cached state of the
+ * drawables it binds to.
+ */
+static void
+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)
+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;
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);
}
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);
}
/**
st_visual_have_buffers(stfb->iface->visual, 1 << statt))
stfb->statts[stfb->num_statts++] = statt;
}
-
- p_atomic_set(&stfb->revalidate, TRUE);
+ stfb->stamp++;
}
/**
&stfb->Base._ColorReadBufferIndex);
stfb->iface = stfbi;
+ stfb->iface_stamp = p_atomic_read(&stfbi->stamp) - 1;
/* add the color buffer */
idx = stfb->Base._ColorDrawBufferIndexes[0];
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;
_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)
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;
}
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);
}
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();
st_framebuffer_validate(stdraw, st);
if (stread && stread != stdraw)
st_framebuffer_validate(stread, st);
+
+ st_context_validate(st, stdraw, stread);
}
/**