@@ -235,3 +235,29 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen, | |||
FREE(r300); | |||
return NULL; | |||
} | |||
void r300_finish(struct r300_context *r300) | |||
{ | |||
struct pipe_framebuffer_state *fb; | |||
unsigned i; | |||
/* This is a preliminary implementation of glFinish. | |||
* | |||
* The ideal implementation should use something like EmitIrqLocked and | |||
* WaitIrq, or better, real fences. | |||
*/ | |||
if (r300->fb_state.state) { | |||
fb = r300->fb_state.state; | |||
for (i = 0; i < fb->nr_cbufs; i++) { | |||
if (fb->cbufs[i]->texture) { | |||
r300->rws->buffer_wait(r300->rws, | |||
r300_texture(fb->cbufs[i]->texture)->buffer); | |||
} | |||
if (fb->zsbuf) { | |||
r300->rws->buffer_wait(r300->rws, | |||
r300_texture(fb->zsbuf->texture)->buffer); | |||
} | |||
} | |||
} | |||
} |
@@ -252,6 +252,22 @@ struct r300_query { | |||
struct r300_query* next; | |||
}; | |||
/* Fence object. | |||
* | |||
* This is a fake fence. Instead of syncing with the fence, we sync | |||
* with the context, which is inefficient but compliant. | |||
* | |||
* This is not a subclass of pipe_fence_handle because pipe_fence_handle is | |||
* never actually fully defined. So, rather than have it as a member, and do | |||
* subclass-style casting, we treat pipe_query as an opaque, and just | |||
* trust that our state tracker does not ever mess up query objects. | |||
*/ | |||
struct r300_fence { | |||
struct pipe_reference reference; | |||
struct r300_context *ctx; | |||
boolean signalled; | |||
}; | |||
struct r300_texture { | |||
/* Parent class */ | |||
struct u_resource b; | |||
@@ -474,6 +490,7 @@ void r300_init_render_functions(struct r300_context *r300); | |||
void r300_init_state_functions(struct r300_context* r300); | |||
void r300_init_resource_functions(struct r300_context* r300); | |||
void r300_finish(struct r300_context *r300); | |||
void r500_dump_rs_block(struct r300_rs_block *rs); | |||
static INLINE boolean CTX_DBG_ON(struct r300_context * ctx, unsigned flags) |
@@ -37,8 +37,7 @@ static void r300_flush(struct pipe_context* pipe, | |||
struct r300_context *r300 = r300_context(pipe); | |||
struct r300_query *query; | |||
struct r300_atom *atom; | |||
struct pipe_framebuffer_state *fb; | |||
unsigned i; | |||
struct r300_fence **rfence = (struct r300_fence**)fence; | |||
CS_LOCALS(r300); | |||
(void) cs_count; | |||
@@ -75,37 +74,10 @@ static void r300_flush(struct pipe_context* pipe, | |||
query->flushed = TRUE; | |||
} | |||
/* XXX | |||
* | |||
* This is a preliminary implementation of glFinish. Note that st/mesa | |||
* uses a non-null fence when glFinish is called and then waits for | |||
* the fence. Instead of returning the actual fence, we do the sync | |||
* directly. | |||
* | |||
* The ideal implementation should use something like EmitIrqLocked and | |||
* WaitIrq, or better, real fences. | |||
* | |||
* This feature degrades performance to the level of r300c for games that | |||
* use glFinish a lot, even openarena does. Ideally we wouldn't need | |||
* glFinish at all if we had proper throttling in swapbuffers so that | |||
* the CPU wouldn't outrun the GPU by several frames, so this is basically | |||
* a temporary fix for the input lag. Once swap&sync works with DRI2, | |||
* I'll be happy to remove this code. | |||
* | |||
* - M. */ | |||
if (fence && r300->fb_state.state) { | |||
fb = r300->fb_state.state; | |||
for (i = 0; i < fb->nr_cbufs; i++) { | |||
if (fb->cbufs[i]->texture) { | |||
r300->rws->buffer_wait(r300->rws, | |||
r300_texture(fb->cbufs[i]->texture)->buffer); | |||
} | |||
if (fb->zsbuf) { | |||
r300->rws->buffer_wait(r300->rws, | |||
r300_texture(fb->zsbuf->texture)->buffer); | |||
} | |||
} | |||
/* Create a new fence. */ | |||
if (rfence) { | |||
*rfence = CALLOC_STRUCT(r300_fence); | |||
(*rfence)->ctx = r300; | |||
} | |||
} | |||
@@ -319,20 +319,33 @@ static void r300_fence_reference(struct pipe_screen *screen, | |||
struct pipe_fence_handle **ptr, | |||
struct pipe_fence_handle *fence) | |||
{ | |||
struct r300_fence **oldf = (struct r300_fence**)ptr; | |||
struct r300_fence *newf = (struct r300_fence*)fence; | |||
if (pipe_reference(&(*oldf)->reference, &newf->reference)) | |||
FREE(*oldf); | |||
*ptr = fence; | |||
} | |||
static int r300_fence_signalled(struct pipe_screen *screen, | |||
struct pipe_fence_handle *fence, | |||
unsigned flags) | |||
{ | |||
return 0; | |||
struct r300_fence *rfence = (struct r300_fence*)fence; | |||
return rfence->signalled ? 0 : 1; /* 0 == success */ | |||
} | |||
static int r300_fence_finish(struct pipe_screen *screen, | |||
struct pipe_fence_handle *fence, | |||
unsigned flags) | |||
{ | |||
return 0; | |||
struct r300_fence *rfence = (struct r300_fence*)fence; | |||
r300_finish(rfence->ctx); | |||
rfence->signalled = TRUE; | |||
return 0; /* 0 == success */ | |||
} | |||
struct pipe_screen* r300_create_screen(struct r300_winsys_screen *rws) |