Previously for frame throttling we would wait on the first batch after a swap before emitting another swap, because we had no hook after a swap was emitted. This meant that if an app managed to squeeze everything it for a frame had into one batch, it would lock-step with the GPU. With the swapbuffers changes, we now have the entrypoint we want. This takes the WoW intro screen from 25% GPU idle and visibly jerky to 4-5% GPU idle and rather smooth. Other apps such as OpenArena have run into this problem as well.tags/7.8-rc1
static void | static void | ||||
intel_glFlush(GLcontext *ctx) | intel_glFlush(GLcontext *ctx) | ||||
{ | { | ||||
struct intel_context *intel = intel_context(ctx); | |||||
intel_flush(ctx, GL_TRUE); | intel_flush(ctx, GL_TRUE); | ||||
/* We're using glFlush as an indicator that a frame is done, which is | |||||
* what DRI2 does before calling SwapBuffers (and means we should catch | |||||
* people doing front-buffer rendering, as well).. | |||||
* | |||||
* Wait for the swapbuffers before the one we just emitted, so we don't | |||||
* get too many swaps outstanding for apps that are GPU-heavy but not | |||||
* CPU-heavy. | |||||
* | |||||
* Unfortunately, we don't have a handle to the batch containing the swap, | |||||
* and getting our hands on that doesn't seem worth it, so we just us the | |||||
* first batch we emitted after the last swap. | |||||
*/ | |||||
if (intel->first_post_swapbuffers_batch != NULL) { | |||||
drm_intel_bo_wait_rendering(intel->first_post_swapbuffers_batch); | |||||
drm_intel_bo_unreference(intel->first_post_swapbuffers_batch); | |||||
intel->first_post_swapbuffers_batch = NULL; | |||||
} | |||||
} | } | ||||
void | void |
static void | static void | ||||
intelDRI2FlushInvalidate(__DRIdrawable *drawable) | intelDRI2FlushInvalidate(__DRIdrawable *drawable) | ||||
{ | { | ||||
struct intel_context *intel = drawable->driContextPriv->driverPrivate; | |||||
intelDRI2Flush(drawable); | intelDRI2Flush(drawable); | ||||
drawable->validBuffers = GL_FALSE; | drawable->validBuffers = GL_FALSE; | ||||
/* We're using FlushInvalidate as an indicator that a frame is | |||||
* done. It's only called immediately after SwapBuffers, so it | |||||
* won't affect front-buffer rendering or applications explicitly | |||||
* managing swap regions using MESA_copy_buffer. | |||||
* | |||||
* Wait for the swapbuffers before the one we just emitted, so we don't | |||||
* get too many swaps outstanding for apps that are GPU-heavy but not | |||||
* CPU-heavy. | |||||
* | |||||
* Unfortunately, we don't have a handle to the batch containing the swap, | |||||
* and getting our hands on that doesn't seem worth it, so we just use the | |||||
* first batch we emitted after the last swap. | |||||
*/ | |||||
if (intel->first_post_swapbuffers_batch != NULL) { | |||||
drm_intel_bo_wait_rendering(intel->first_post_swapbuffers_batch); | |||||
drm_intel_bo_unreference(intel->first_post_swapbuffers_batch); | |||||
intel->first_post_swapbuffers_batch = NULL; | |||||
} | |||||
} | } | ||||
static const struct __DRI2flushExtensionRec intelFlushExtension = { | static const struct __DRI2flushExtensionRec intelFlushExtension = { |