From 8b145e23023927ddec7839a9e4498d5a42e3ca29 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Feb 2011 13:05:31 +0100 Subject: st/egl: Implement swapbuffer throttling When doing copy swapbuffers using drm, throttle on outstanding copy operations. Introduces a new environment variable, EGL_THROTTLE_FENCES that the user can use to indicate the desired number of outstanding swapbuffers, or disable throttling using EGL_THROTTLE_FENCES=0. This can and perhaps should be extended to the pageflip case as well, since with some hardware pageflips can be pipelined. In case the pageflip syncs, the throttle operation will be a no-op anyway. Update copyright notices. Signed-off-by: Thomas Hellstrom --- .../state_trackers/egl/common/native_helper.c | 103 ++++++++++++++++++++- .../state_trackers/egl/common/native_helper.h | 27 ++++++ src/gallium/state_trackers/egl/drm/modeset.c | 15 ++- 3 files changed, 141 insertions(+), 4 deletions(-) (limited to 'src/gallium/state_trackers') diff --git a/src/gallium/state_trackers/egl/common/native_helper.c b/src/gallium/state_trackers/egl/common/native_helper.c index 0f00c4d13e..be6713d03a 100644 --- a/src/gallium/state_trackers/egl/common/native_helper.c +++ b/src/gallium/state_trackers/egl/common/native_helper.c @@ -3,6 +3,7 @@ * Version: 7.9 * * Copyright (C) 2010 LunarG Inc. + * Copyright (C) 2011 VMware Inc. 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"), @@ -24,6 +25,7 @@ * * Authors: * Chia-I Wu + * Thomas Hellstrom */ #include "util/u_inlines.h" @@ -34,6 +36,14 @@ #include "native_helper.h" +/** + * Number of swap fences and mask + */ + +#define EGL_SWAP_FENCES_MAX 4 +#define EGL_SWAP_FENCES_MASK 3 +#define EGL_SWAP_FENCES_DEFAULT 1 + struct resource_surface { struct pipe_screen *screen; enum pipe_format format; @@ -42,6 +52,15 @@ struct resource_surface { struct pipe_resource *resources[NUM_NATIVE_ATTACHMENTS]; uint resource_mask; uint width, height; + + /** + * Swap fences. + */ + struct pipe_fence_handle *swap_fences[EGL_SWAP_FENCES_MAX]; + unsigned int cur_fences; + unsigned int head; + unsigned int tail; + unsigned int desired_fences; }; struct resource_surface * @@ -49,11 +68,16 @@ resource_surface_create(struct pipe_screen *screen, enum pipe_format format, uint bind) { struct resource_surface *rsurf = CALLOC_STRUCT(resource_surface); + char *swap_fences = getenv("EGL_THROTTLE_FENCES"); if (rsurf) { rsurf->screen = screen; rsurf->format = format; rsurf->bind = bind; + rsurf->desired_fences = (swap_fences) ? atoi(swap_fences) : + EGL_SWAP_FENCES_DEFAULT; + if (rsurf->desired_fences > EGL_SWAP_FENCES_MAX) + rsurf->desired_fences = EGL_SWAP_FENCES_MAX; } return rsurf; @@ -256,7 +280,6 @@ resource_surface_copy_swap(struct resource_surface *rsurf, u_box_origin_2d(ftex->width0, ftex->height0, &src_box); pipe->resource_copy_region(pipe, ftex, 0, 0, 0, 0, btex, 0, &src_box); - pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); ret = TRUE; out_no_ftex: @@ -266,3 +289,81 @@ resource_surface_copy_swap(struct resource_surface *rsurf, return ret; } + +static struct pipe_fence_handle * +swap_fences_pop_front(struct resource_surface *rsurf) +{ + struct pipe_screen *screen = rsurf->screen; + struct pipe_fence_handle *fence = NULL; + + if (rsurf->desired_fences == 0) + return NULL; + + if (rsurf->cur_fences >= rsurf->desired_fences) { + screen->fence_reference(screen, &fence, rsurf->swap_fences[rsurf->tail]); + screen->fence_reference(screen, &rsurf->swap_fences[rsurf->tail++], NULL); + rsurf->tail &= EGL_SWAP_FENCES_MASK; + --rsurf->cur_fences; + } + return fence; +} + +static void +swap_fences_push_back(struct resource_surface *rsurf, + struct pipe_fence_handle *fence) +{ + struct pipe_screen *screen = rsurf->screen; + + if (!fence || rsurf->desired_fences == 0) + return; + + while(rsurf->cur_fences == rsurf->desired_fences) + swap_fences_pop_front(rsurf); + + rsurf->cur_fences++; + screen->fence_reference(screen, &rsurf->swap_fences[rsurf->head++], + fence); + rsurf->head &= EGL_SWAP_FENCES_MASK; +} + +boolean +resource_surface_throttle(struct resource_surface *rsurf) +{ + struct pipe_screen *screen = rsurf->screen; + struct pipe_fence_handle *fence = swap_fences_pop_front(rsurf); + + if (fence) { + (void) screen->fence_finish(screen, fence, 0); + screen->fence_reference(screen, &fence, NULL); + return TRUE; + } + + return FALSE; +} + +boolean +resource_surface_flush(struct resource_surface *rsurf, + struct native_display *ndpy) +{ + struct pipe_fence_handle *fence = NULL; + struct pipe_screen *screen = rsurf->screen; + struct pipe_context *pipe= ndpy_get_copy_context(ndpy); + + if (!pipe) + return FALSE; + + pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, &fence); + if (fence == NULL) + return FALSE; + + swap_fences_push_back(rsurf, fence); + screen->fence_reference(screen, &fence, NULL); + + return TRUE; +} + +void +resource_surface_wait(struct resource_surface *rsurf) +{ + while (resource_surface_throttle(rsurf)); +} diff --git a/src/gallium/state_trackers/egl/common/native_helper.h b/src/gallium/state_trackers/egl/common/native_helper.h index ad6827336a..39564a0436 100644 --- a/src/gallium/state_trackers/egl/common/native_helper.h +++ b/src/gallium/state_trackers/egl/common/native_helper.h @@ -3,6 +3,7 @@ * Version: 7.9 * * Copyright (C) 2010 LunarG Inc. + * Copyright (C) 2011 VMware Inc. 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"), @@ -24,6 +25,7 @@ * * Authors: * Chia-I Wu + * Thomas Hellstrom */ #include "native.h" @@ -75,6 +77,31 @@ resource_surface_present(struct resource_surface *rsurf, enum native_attachment which, void *winsys_drawable_handle); +/** + * Perform a gallium copy blit between the back left and front left + * surfaces. Needs to be followed by a call to resource_surface_flush. + */ boolean resource_surface_copy_swap(struct resource_surface *rsurf, struct native_display *ndpy); + +/** + * Throttle on outstanding rendering using the copy context. For example + * copy swaps. + */ +boolean +resource_surface_throttle(struct resource_surface *rsurf); + +/** + * Flush pending rendering using the copy context. This function saves a + * marker for upcoming throttles. + */ +boolean +resource_surface_flush(struct resource_surface *rsurf, + struct native_display *ndpy); +/** + * Wait for all rendering using the copy context to be complete. Frees all + * throttle markers saved using resource_surface_flush. + */ +void +resource_surface_wait(struct resource_surface *rsurf); diff --git a/src/gallium/state_trackers/egl/drm/modeset.c b/src/gallium/state_trackers/egl/drm/modeset.c index 6eaa42fafb..3fff954090 100644 --- a/src/gallium/state_trackers/egl/drm/modeset.c +++ b/src/gallium/state_trackers/egl/drm/modeset.c @@ -3,6 +3,7 @@ * Version: 7.9 * * Copyright (C) 2010 LunarG Inc. + * Copyright (C) 2011 VMware Inc. 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"), @@ -24,6 +25,7 @@ * * Authors: * Chia-I Wu + * Thomas Hellstrom */ #include "util/u_memory.h" @@ -136,8 +138,12 @@ drm_surface_copy_swap(struct native_surface *nsurf) struct drm_surface *drmsurf = drm_surface(nsurf); struct drm_display *drmdpy = drmsurf->drmdpy; - if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base) || - !drm_surface_flush_frontbuffer(nsurf)) + (void) resource_surface_throttle(drmsurf->rsurf); + if (!resource_surface_copy_swap(drmsurf->rsurf, &drmdpy->base)) + return FALSE; + + (void) resource_surface_flush(drmsurf->rsurf, &drmdpy->base); + if (!drm_surface_flush_frontbuffer(nsurf)) return FALSE; drmsurf->sequence_number++; @@ -218,7 +224,9 @@ drm_surface_present(struct native_surface *nsurf, static void drm_surface_wait(struct native_surface *nsurf) { - /* no-op */ + struct drm_surface *drmsurf = drm_surface(nsurf); + + resource_surface_wait(drmsurf->rsurf); } static void @@ -226,6 +234,7 @@ drm_surface_destroy(struct native_surface *nsurf) { struct drm_surface *drmsurf = drm_surface(nsurf); + resource_surface_wait(drmsurf->rsurf); if (drmsurf->current_crtc.crtc) drmModeFreeCrtc(drmsurf->current_crtc.crtc); -- cgit v1.2.3