diff options
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/state_trackers/dri/common/dri_drawable.c | 126 | ||||
-rw-r--r-- | src/gallium/state_trackers/dri/common/dri_drawable.h | 12 |
2 files changed, 136 insertions, 2 deletions
diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.c b/src/gallium/state_trackers/dri/common/dri_drawable.c index 7b8de3174be..ca9e1307db9 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.c +++ b/src/gallium/state_trackers/dri/common/dri_drawable.c @@ -37,7 +37,9 @@ #include "util/u_format.h" #include "util/u_memory.h" #include "util/u_inlines.h" - + +static void +swap_fences_unref(struct dri_drawable *draw); static boolean dri_st_framebuffer_validate(struct st_framebuffer_iface *stfbi, @@ -135,6 +137,8 @@ dri_create_buffer(__DRIscreen * sPriv, drawable->screen = screen; drawable->sPriv = sPriv; drawable->dPriv = dPriv; + drawable->desired_fences = 2; + dPriv->driverPrivate = (void *)drawable; p_atomic_set(&drawable->base.stamp, 1); @@ -155,6 +159,8 @@ dri_destroy_buffer(__DRIdrawable * dPriv) for (i = 0; i < ST_ATTACHMENT_COUNT; i++) pipe_resource_reference(&drawable->textures[i], NULL); + swap_fences_unref(drawable); + FREE(drawable); } @@ -266,4 +272,122 @@ dri_drawable_get_format(struct dri_drawable *drawable, } } + +/** + * swap_fences_pop_front - pull a fence from the throttle queue + * + * If the throttle queue is filled to the desired number of fences, + * pull fences off the queue until the number is less than the desired + * number of fences, and return the last fence pulled. + */ +static struct pipe_fence_handle * +swap_fences_pop_front(struct dri_drawable *draw) +{ + struct pipe_screen *screen = draw->screen->base.screen; + struct pipe_fence_handle *fence = NULL; + + if (draw->desired_fences == 0) + return NULL; + + if (draw->cur_fences >= draw->desired_fences) { + screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]); + screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); + draw->tail &= DRI_SWAP_FENCES_MASK; + --draw->cur_fences; + } + return fence; +} + + +/** + * swap_fences_push_back - push a fence onto the throttle queue + * + * push a fence onto the throttle queue and pull fences of the queue + * so that the desired number of fences are on the queue. + */ +static void +swap_fences_push_back(struct dri_drawable *draw, + struct pipe_fence_handle *fence) +{ + struct pipe_screen *screen = draw->screen->base.screen; + + if (!fence || draw->desired_fences == 0) + return; + + while(draw->cur_fences == draw->desired_fences) + swap_fences_pop_front(draw); + + draw->cur_fences++; + screen->fence_reference(screen, &draw->swap_fences[draw->head++], + fence); + draw->head &= DRI_SWAP_FENCES_MASK; +} + + +/** + * swap_fences_unref - empty the throttle queue + * + * pulls fences of the throttle queue until it is empty. + */ +static void +swap_fences_unref(struct dri_drawable *draw) +{ + struct pipe_screen *screen = draw->screen->base.screen; + + while(draw->cur_fences) { + screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL); + draw->tail &= DRI_SWAP_FENCES_MASK; + --draw->cur_fences; + } +} + + +/** + * dri_throttle - A DRI2ThrottleExtension throttling function. + * + * pulls a fence off the throttling queue and waits for it if the + * number of fences on the throttling queue has reached the desired + * number. + * + * Then flushes to insert a fence at the current rendering position, and + * pushes that fence on the queue. This requires that the st_context_iface + * flush method returns a fence even if there are no commands to flush. + */ +static void +dri_throttle(__DRIcontext *driCtx, __DRIdrawable *dPriv, + enum __DRI2throttleReason reason) +{ + struct dri_drawable *draw = dri_drawable(dPriv); + struct st_context_iface *ctxi; + struct pipe_screen *screen = draw->screen->base.screen; + struct pipe_fence_handle *fence; + + if (reason != __DRI2_THROTTLE_SWAPBUFFER && + reason != __DRI2_THROTTLE_FLUSHFRONT) + return; + + fence = swap_fences_pop_front(draw); + if (fence) { + (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE); + screen->fence_reference(screen, &fence, NULL); + } + + if (driCtx == NULL) + return; + + ctxi = dri_context(driCtx)->st; + ctxi->flush(ctxi, 0, &fence); + if (fence) { + swap_fences_push_back(draw, fence); + screen->fence_reference(screen, &fence, NULL); + } +} + + +const __DRI2throttleExtension dri2ThrottleExtension = { + .base = { __DRI2_THROTTLE, __DRI2_THROTTLE_VERSION }, + .throttle = dri_throttle, +}; + + /* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/state_trackers/dri/common/dri_drawable.h b/src/gallium/state_trackers/dri/common/dri_drawable.h index fd3460dd30b..007421ebe18 100644 --- a/src/gallium/state_trackers/dri/common/dri_drawable.h +++ b/src/gallium/state_trackers/dri/common/dri_drawable.h @@ -36,6 +36,10 @@ struct pipe_surface; struct st_framebuffer; struct dri_context; +#define DRI_SWAP_FENCES_MAX 4 +#define DRI_SWAP_FENCES_MASK 3 +#define DRI_SWAP_FENCES_DEFAULT 1 + struct dri_drawable { struct st_framebuffer_iface base; @@ -55,6 +59,12 @@ struct dri_drawable struct pipe_resource *textures[ST_ATTACHMENT_COUNT]; unsigned int texture_mask, texture_stamp; + struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX]; + unsigned int cur_fences; + unsigned int head; + unsigned int tail; + unsigned int desired_fences; + /* used only by DRISW */ struct pipe_surface *drisw_surface; @@ -93,7 +103,7 @@ dri_drawable_get_format(struct dri_drawable *drawable, unsigned *bind); extern const __DRItexBufferExtension driTexBufferExtension; - +extern const __DRI2throttleExtension dri2ThrottleExtension; #endif /* vim: set sw=3 ts=8 sts=3 expandtab: */ |