From 06657fa203a46c37042e87d05d741439857156c7 Mon Sep 17 00:00:00 2001 From: Axel Davy Date: Sat, 19 Nov 2016 12:39:31 +0100 Subject: [PATCH] st/nine: Rework buffer presentation path Use the new API for DISCARD. Signed-off-by: Axel Davy --- src/gallium/state_trackers/nine/swapchain9.c | 178 ++++++++++++++----- 1 file changed, 131 insertions(+), 47 deletions(-) diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c index 431966d6543..79530f5319e 100644 --- a/src/gallium/state_trackers/nine/swapchain9.c +++ b/src/gallium/state_trackers/nine/swapchain9.c @@ -67,6 +67,15 @@ NineSwapChain9_ctor( struct NineSwapChain9 *This, This->mode = NULL; ID3DPresent_AddRef(pPresent); + if (!This->actx->thread_submit && + This->base.device->minor_version_num > 2) { + D3DPRESENT_PARAMETERS2 params2; + + memset(¶ms2, 0, sizeof(D3DPRESENT_PARAMETERS2)); + params2.AllowDISCARDDelayedRelease = TRUE; + params2.TearFreeDISCARD = FALSE; + ID3DPresent_SetPresentParameters2(pPresent, ¶ms2); + } if (!pPresentationParameters->hDeviceWindow) pPresentationParameters->hDeviceWindow = hFocusWindow; @@ -114,6 +123,10 @@ D3DWindowBuffer_create(struct NineSwapChain9 *This, return ret; } +static int +NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams ); + HRESULT NineSwapChain9_Resize( struct NineSwapChain9 *This, D3DPRESENT_PARAMETERS *pParams, @@ -203,12 +216,8 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This, if (hr != D3D_OK) return hr; - /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. - * Here we don't get back the initial content of the screen. To emulate the behaviour - * we allocate an additional buffer */ oldBufferCount = This->num_back_buffers; - newBufferCount = pParams->BackBufferCount + - (pParams->SwapEffect != D3DSWAPEFFECT_COPY); + newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams); multisample_type = pParams->MultiSampleType; @@ -799,59 +808,94 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, if (hr == D3DERR_WASSTILLDRAWING) return hr; - switch (This->params.SwapEffect) { - case D3DSWAPEFFECT_FLIP: - UNTESTED(4); - case D3DSWAPEFFECT_DISCARD: - /* rotate the queue */ - pipe_resource_reference(&res, This->buffers[0]->base.resource); + if (This->base.device->minor_version_num > 2 && + This->params.SwapEffect == D3DSWAPEFFECT_DISCARD && + This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && + !This->actx->thread_submit) { + int next_buffer = -1; + + while (next_buffer == -1) { + /* Find a free backbuffer */ for (i = 1; i < This->num_back_buffers; i++) { - NineSurface9_SetResourceResize(This->buffers[i - 1], - This->buffers[i]->base.resource); + if (ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) { + DBG("Found buffer released: %d\n", i); + next_buffer = i; + break; + } } - NineSurface9_SetResourceResize( - This->buffers[This->num_back_buffers - 1], res); + if (next_buffer == -1) { + DBG("Found no buffer released. Waiting for event\n"); + ID3DPresent_WaitBufferReleaseEvent(This->present); + } + } + /* Switch with the released buffer */ + pipe_resource_reference(&res, This->buffers[0]->base.resource); + NineSurface9_SetResourceResize( + This->buffers[0], This->buffers[next_buffer]->base.resource); + NineSurface9_SetResourceResize( + This->buffers[next_buffer], res); + pipe_resource_reference(&res, NULL); + + if (This->present_buffers[0]) { + pipe_resource_reference(&res, This->present_buffers[0]); + pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]); + pipe_resource_reference(&This->present_buffers[next_buffer], res); pipe_resource_reference(&res, NULL); + } - if (This->present_buffers[0]) { - pipe_resource_reference(&res, This->present_buffers[0]); - for (i = 1; i < This->num_back_buffers; i++) - pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); - pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); + handle_temp = This->present_handles[0]; + This->present_handles[0] = This->present_handles[next_buffer]; + This->present_handles[next_buffer] = handle_temp; + + /* Path not yet compatible with thread_submit */ + assert(!This->tasks[0] && !This->tasks[next_buffer]); + } else { + switch (This->params.SwapEffect) { + case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */ + case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */ + case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */ + case D3DSWAPEFFECT_FLIP: + /* rotate the queue */ + pipe_resource_reference(&res, This->buffers[0]->base.resource); + for (i = 1; i < This->num_back_buffers; i++) { + NineSurface9_SetResourceResize(This->buffers[i - 1], + This->buffers[i]->base.resource); + } + NineSurface9_SetResourceResize( + This->buffers[This->num_back_buffers - 1], res); pipe_resource_reference(&res, NULL); - } - handle_temp = This->present_handles[0]; - for (i = 1; i < This->num_back_buffers; i++) { - This->present_handles[i-1] = This->present_handles[i]; - } - This->present_handles[This->num_back_buffers - 1] = handle_temp; - task_temp = This->tasks[0]; - for (i = 1; i < This->num_back_buffers; i++) { - This->tasks[i-1] = This->tasks[i]; - } - This->tasks[This->num_back_buffers - 1] = task_temp; - break; + if (This->present_buffers[0]) { + pipe_resource_reference(&res, This->present_buffers[0]); + for (i = 1; i < This->num_back_buffers; i++) + pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); + pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); + pipe_resource_reference(&res, NULL); + } - case D3DSWAPEFFECT_COPY: - UNTESTED(5); - /* do nothing */ - break; + handle_temp = This->present_handles[0]; + for (i = 1; i < This->num_back_buffers; i++) { + This->present_handles[i-1] = This->present_handles[i]; + } + This->present_handles[This->num_back_buffers - 1] = handle_temp; + task_temp = This->tasks[0]; + for (i = 1; i < This->num_back_buffers; i++) { + This->tasks[i-1] = This->tasks[i]; + } + This->tasks[This->num_back_buffers - 1] = task_temp; + break; - case D3DSWAPEFFECT_OVERLAY: - /* XXX not implemented */ - break; + case D3DSWAPEFFECT_COPY: + /* do nothing */ + break; + } - case D3DSWAPEFFECT_FLIPEX: - /* XXX not implemented */ - break; + if (This->tasks[0]) + _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); + + ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); } - if (This->tasks[0]) - _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); - - ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); - This->base.device->state.changed.group |= NINE_STATE_FB; return hr; @@ -1048,3 +1092,43 @@ NineSwapChain9_WaitForThread( struct NineSwapChain9 *This, (void) ID3DPresent_WaitForThread(This->present, thread); } } + +static int +NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, + D3DPRESENT_PARAMETERS *pParams ) +{ + int count = pParams->BackBufferCount; + + /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. + * Here we don't get back the initial content of the screen. To emulate the behaviour + * we allocate an additional buffer */ + if (pParams->SwapEffect != D3DSWAPEFFECT_COPY) + count++; + /* With DISCARD, as there is no guarantee about the buffer contents, we can use + * an arbitrary number of buffers */ + if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) { + /* thread_submit has a throttling equivalent to the throttling + * with throttling_value set to count-1. Most drivers use + * 2 for throttling_value. For performance use count of at least 3 + * for thread_submit. */ + if (This->actx->thread_submit && count < 3) + count = 3; + /* When we enable AllowDISCARDDelayedRelease, we must ensure + * to have at least 4 buffers to meet INTERVAL_IMMEDIATE, + * since the display server/compositor can hold 3 buffers + * without releasing them: + * . Buffer on screen. + * . Buffer scheduled kernel side to be next on screen. + * . Last buffer sent. + * For some reasons, 5 buffers are actually needed, because in + * case a pageflip is missed because rendering wasn't finished, + * the Xserver will hold 4 buffers. */ + if (!This->actx->thread_submit && + This->base.device->minor_version_num > 2 && + pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && + count < 5) + count = 5; + } + + return count; +}