17ec681f3Smrg/* 27ec681f3Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 87ec681f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom 97ec681f3Smrg * the Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 197ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 207ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 217ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 227ec681f3Smrg 237ec681f3Smrg#include "swapchain9.h" 247ec681f3Smrg#include "surface9.h" 257ec681f3Smrg#include "device9.h" 267ec681f3Smrg 277ec681f3Smrg#include "nine_helpers.h" 287ec681f3Smrg#include "nine_pipe.h" 297ec681f3Smrg#include "nine_dump.h" 307ec681f3Smrg 317ec681f3Smrg#include "util/u_atomic.h" 327ec681f3Smrg#include "util/u_inlines.h" 337ec681f3Smrg#include "util/u_surface.h" 347ec681f3Smrg#include "hud/hud_context.h" 357ec681f3Smrg#include "frontend/drm_driver.h" 367ec681f3Smrg 377ec681f3Smrg#include "threadpool.h" 387ec681f3Smrg 397ec681f3Smrg#define DBG_CHANNEL DBG_SWAPCHAIN 407ec681f3Smrg 417ec681f3Smrg#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n) 427ec681f3Smrg 437ec681f3SmrgHRESULT 447ec681f3SmrgNineSwapChain9_ctor( struct NineSwapChain9 *This, 457ec681f3Smrg struct NineUnknownParams *pParams, 467ec681f3Smrg BOOL implicit, 477ec681f3Smrg ID3DPresent *pPresent, 487ec681f3Smrg D3DPRESENT_PARAMETERS *pPresentationParameters, 497ec681f3Smrg struct d3dadapter9_context *pCTX, 507ec681f3Smrg HWND hFocusWindow, 517ec681f3Smrg D3DDISPLAYMODEEX *mode ) 527ec681f3Smrg{ 537ec681f3Smrg HRESULT hr; 547ec681f3Smrg int i; 557ec681f3Smrg 567ec681f3Smrg DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n", 577ec681f3Smrg This, pParams->device, pPresent, pCTX, hFocusWindow); 587ec681f3Smrg 597ec681f3Smrg hr = NineUnknown_ctor(&This->base, pParams); 607ec681f3Smrg if (FAILED(hr)) 617ec681f3Smrg return hr; 627ec681f3Smrg 637ec681f3Smrg This->screen = NineDevice9_GetScreen(This->base.device); 647ec681f3Smrg This->implicit = implicit; 657ec681f3Smrg This->actx = pCTX; 667ec681f3Smrg This->present = pPresent; 677ec681f3Smrg This->mode = NULL; 687ec681f3Smrg 697ec681f3Smrg ID3DPresent_AddRef(pPresent); 707ec681f3Smrg if (This->base.device->minor_version_num > 2) { 717ec681f3Smrg D3DPRESENT_PARAMETERS2 params2; 727ec681f3Smrg 737ec681f3Smrg memset(¶ms2, 0, sizeof(D3DPRESENT_PARAMETERS2)); 747ec681f3Smrg params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release; 757ec681f3Smrg params2.TearFreeDISCARD = This->actx->tearfree_discard; 767ec681f3Smrg ID3DPresent_SetPresentParameters2(pPresent, ¶ms2); 777ec681f3Smrg } 787ec681f3Smrg 797ec681f3Smrg if (!pPresentationParameters->hDeviceWindow) 807ec681f3Smrg pPresentationParameters->hDeviceWindow = hFocusWindow; 817ec681f3Smrg 827ec681f3Smrg This->rendering_done = FALSE; 837ec681f3Smrg This->pool = NULL; 847ec681f3Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 857ec681f3Smrg This->pending_presentation[i] = calloc(1, sizeof(BOOL)); 867ec681f3Smrg if (!This->pending_presentation[i]) 877ec681f3Smrg return E_OUTOFMEMORY; 887ec681f3Smrg } 897ec681f3Smrg return NineSwapChain9_Resize(This, pPresentationParameters, mode); 907ec681f3Smrg} 917ec681f3Smrg 927ec681f3Smrgstatic D3DWindowBuffer * 937ec681f3SmrgD3DWindowBuffer_create(struct NineSwapChain9 *This, 947ec681f3Smrg struct pipe_resource *resource, 957ec681f3Smrg int depth, 967ec681f3Smrg int for_frontbuffer_reading) 977ec681f3Smrg{ 987ec681f3Smrg D3DWindowBuffer *ret; 997ec681f3Smrg struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device); 1007ec681f3Smrg struct winsys_handle whandle; 1017ec681f3Smrg int stride, dmaBufFd; 1027ec681f3Smrg HRESULT hr; 1037ec681f3Smrg 1047ec681f3Smrg memset(&whandle, 0, sizeof(whandle)); 1057ec681f3Smrg whandle.type = WINSYS_HANDLE_TYPE_FD; 1067ec681f3Smrg This->screen->resource_get_handle(This->screen, pipe, resource, 1077ec681f3Smrg &whandle, 1087ec681f3Smrg for_frontbuffer_reading ? 1097ec681f3Smrg PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE : 1107ec681f3Smrg PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); 1117ec681f3Smrg nine_context_get_pipe_release(This->base.device); 1127ec681f3Smrg stride = whandle.stride; 1137ec681f3Smrg dmaBufFd = whandle.handle; 1147ec681f3Smrg hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present, 1157ec681f3Smrg dmaBufFd, 1167ec681f3Smrg resource->width0, 1177ec681f3Smrg resource->height0, 1187ec681f3Smrg stride, 1197ec681f3Smrg depth, 1207ec681f3Smrg 32, 1217ec681f3Smrg &ret); 1227ec681f3Smrg assert (SUCCEEDED(hr)); 1237ec681f3Smrg 1247ec681f3Smrg if (FAILED(hr)) { 1257ec681f3Smrg ERR("Failed to create new D3DWindowBufferFromDmaBuf\n"); 1267ec681f3Smrg return NULL; 1277ec681f3Smrg } 1287ec681f3Smrg return ret; 1297ec681f3Smrg} 1307ec681f3Smrg 1317ec681f3Smrgstatic void 1327ec681f3SmrgD3DWindowBuffer_release(struct NineSwapChain9 *This, 1337ec681f3Smrg D3DWindowBuffer *present_handle) 1347ec681f3Smrg{ 1357ec681f3Smrg int i; 1367ec681f3Smrg 1377ec681f3Smrg /* IsBufferReleased API not available */ 1387ec681f3Smrg if (This->base.device->minor_version_num <= 2) { 1397ec681f3Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, present_handle); 1407ec681f3Smrg return; 1417ec681f3Smrg } 1427ec681f3Smrg 1437ec681f3Smrg /* Add it to the 'pending release' list */ 1447ec681f3Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 1457ec681f3Smrg if (!This->present_handles_pending_release[i]) { 1467ec681f3Smrg This->present_handles_pending_release[i] = present_handle; 1477ec681f3Smrg break; 1487ec681f3Smrg } 1497ec681f3Smrg } 1507ec681f3Smrg if (i == (D3DPRESENT_BACK_BUFFERS_MAX_EX + 1)) { 1517ec681f3Smrg ERR("Server not releasing buffers...\n"); 1527ec681f3Smrg assert(false); 1537ec681f3Smrg } 1547ec681f3Smrg 1557ec681f3Smrg /* Destroy elements of the list released by the server */ 1567ec681f3Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 1577ec681f3Smrg if (This->present_handles_pending_release[i] && 1587ec681f3Smrg ID3DPresent_IsBufferReleased(This->present, This->present_handles_pending_release[i])) { 1597ec681f3Smrg /* WaitBufferReleased also waits the presentation feedback 1607ec681f3Smrg * (which should arrive at about the same time), 1617ec681f3Smrg * while IsBufferReleased doesn't. DestroyD3DWindowBuffer unfortunately 1627ec681f3Smrg * checks it to release immediately all data, else the release 1637ec681f3Smrg * is postponed for This->present release. To avoid leaks (we may handle 1647ec681f3Smrg * a lot of resize), call WaitBufferReleased. */ 1657ec681f3Smrg ID3DPresent_WaitBufferReleased(This->present, This->present_handles_pending_release[i]); 1667ec681f3Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); 1677ec681f3Smrg This->present_handles_pending_release[i] = NULL; 1687ec681f3Smrg } 1697ec681f3Smrg } 1707ec681f3Smrg} 1717ec681f3Smrg 1727ec681f3Smrgstatic int 1737ec681f3SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, 1747ec681f3Smrg D3DPRESENT_PARAMETERS *pParams ); 1757ec681f3Smrg 1767ec681f3SmrgHRESULT 1777ec681f3SmrgNineSwapChain9_Resize( struct NineSwapChain9 *This, 1787ec681f3Smrg D3DPRESENT_PARAMETERS *pParams, 1797ec681f3Smrg D3DDISPLAYMODEEX *mode ) 1807ec681f3Smrg{ 1817ec681f3Smrg struct NineDevice9 *pDevice = This->base.device; 1827ec681f3Smrg D3DSURFACE_DESC desc; 1837ec681f3Smrg HRESULT hr; 1847ec681f3Smrg struct pipe_resource *resource, tmplt; 1857ec681f3Smrg enum pipe_format pf; 1867ec681f3Smrg BOOL has_present_buffers = FALSE; 1877ec681f3Smrg int depth; 1887ec681f3Smrg unsigned i, oldBufferCount, newBufferCount; 1897ec681f3Smrg D3DMULTISAMPLE_TYPE multisample_type; 1907ec681f3Smrg 1917ec681f3Smrg DBG("This=%p pParams=%p\n", This, pParams); 1927ec681f3Smrg user_assert(pParams != NULL, E_POINTER); 1937ec681f3Smrg user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL); 1947ec681f3Smrg user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) || 1957ec681f3Smrg (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL); 1967ec681f3Smrg user_assert(pDevice->ex || pParams->BackBufferCount <= 1977ec681f3Smrg D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL); 1987ec681f3Smrg user_assert(!pDevice->ex || pParams->BackBufferCount <= 1997ec681f3Smrg D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL); 2007ec681f3Smrg user_assert(pDevice->ex || 2017ec681f3Smrg (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) || 2027ec681f3Smrg (pParams->SwapEffect == D3DSWAPEFFECT_COPY) || 2037ec681f3Smrg (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL); 2047ec681f3Smrg 2057ec681f3Smrg DBG("pParams(%p):\n" 2067ec681f3Smrg "BackBufferWidth: %u\n" 2077ec681f3Smrg "BackBufferHeight: %u\n" 2087ec681f3Smrg "BackBufferFormat: %s\n" 2097ec681f3Smrg "BackBufferCount: %u\n" 2107ec681f3Smrg "MultiSampleType: %u\n" 2117ec681f3Smrg "MultiSampleQuality: %u\n" 2127ec681f3Smrg "SwapEffect: %u\n" 2137ec681f3Smrg "hDeviceWindow: %p\n" 2147ec681f3Smrg "Windowed: %i\n" 2157ec681f3Smrg "EnableAutoDepthStencil: %i\n" 2167ec681f3Smrg "AutoDepthStencilFormat: %s\n" 2177ec681f3Smrg "Flags: %s\n" 2187ec681f3Smrg "FullScreen_RefreshRateInHz: %u\n" 2197ec681f3Smrg "PresentationInterval: %x\n", pParams, 2207ec681f3Smrg pParams->BackBufferWidth, pParams->BackBufferHeight, 2217ec681f3Smrg d3dformat_to_string(pParams->BackBufferFormat), 2227ec681f3Smrg pParams->BackBufferCount, 2237ec681f3Smrg pParams->MultiSampleType, pParams->MultiSampleQuality, 2247ec681f3Smrg pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed, 2257ec681f3Smrg pParams->EnableAutoDepthStencil, 2267ec681f3Smrg d3dformat_to_string(pParams->AutoDepthStencilFormat), 2277ec681f3Smrg nine_D3DPRESENTFLAG_to_str(pParams->Flags), 2287ec681f3Smrg pParams->FullScreen_RefreshRateInHz, 2297ec681f3Smrg pParams->PresentationInterval); 2307ec681f3Smrg 2317ec681f3Smrg if (pParams->BackBufferCount == 0) { 2327ec681f3Smrg pParams->BackBufferCount = 1; 2337ec681f3Smrg } 2347ec681f3Smrg 2357ec681f3Smrg if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) { 2367ec681f3Smrg pParams->BackBufferFormat = D3DFMT_A8R8G8B8; 2377ec681f3Smrg } 2387ec681f3Smrg 2397ec681f3Smrg This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0; 2407ec681f3Smrg /* +1 because we add the fence of the current buffer before popping an old one */ 2417ec681f3Smrg if (This->desired_fences > DRI_SWAP_FENCES_MAX) 2427ec681f3Smrg This->desired_fences = DRI_SWAP_FENCES_MAX; 2437ec681f3Smrg 2447ec681f3Smrg if (This->actx->vblank_mode == 0) 2457ec681f3Smrg pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 2467ec681f3Smrg else if (This->actx->vblank_mode == 3) 2477ec681f3Smrg pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE; 2487ec681f3Smrg 2497ec681f3Smrg if (mode && This->mode) { 2507ec681f3Smrg *(This->mode) = *mode; 2517ec681f3Smrg } else if (mode) { 2527ec681f3Smrg This->mode = malloc(sizeof(D3DDISPLAYMODEEX)); 2537ec681f3Smrg memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX)); 2547ec681f3Smrg } else { 2557ec681f3Smrg free(This->mode); 2567ec681f3Smrg This->mode = NULL; 2577ec681f3Smrg } 2587ec681f3Smrg 2597ec681f3Smrg /* Note: It is the role of the backend to fill if necessary 2607ec681f3Smrg * BackBufferWidth and BackBufferHeight */ 2617ec681f3Smrg hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); 2627ec681f3Smrg if (hr != D3D_OK) 2637ec681f3Smrg return hr; 2647ec681f3Smrg 2657ec681f3Smrg oldBufferCount = This->num_back_buffers; 2667ec681f3Smrg newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams); 2677ec681f3Smrg 2687ec681f3Smrg multisample_type = pParams->MultiSampleType; 2697ec681f3Smrg 2707ec681f3Smrg /* Map MultiSampleQuality to MultiSampleType */ 2717ec681f3Smrg hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat, 2727ec681f3Smrg &multisample_type, 2737ec681f3Smrg pParams->MultiSampleQuality, 2747ec681f3Smrg NULL); 2757ec681f3Smrg if (FAILED(hr)) { 2767ec681f3Smrg return hr; 2777ec681f3Smrg } 2787ec681f3Smrg 2797ec681f3Smrg pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat, 2807ec681f3Smrg PIPE_TEXTURE_2D, multisample_type, 2817ec681f3Smrg PIPE_BIND_RENDER_TARGET, FALSE, FALSE); 2827ec681f3Smrg 2837ec681f3Smrg if (This->actx->linear_framebuffer || 2847ec681f3Smrg (pf != PIPE_FORMAT_B8G8R8X8_UNORM && 2857ec681f3Smrg pf != PIPE_FORMAT_B8G8R8A8_UNORM) || 2867ec681f3Smrg pParams->SwapEffect != D3DSWAPEFFECT_DISCARD || 2877ec681f3Smrg multisample_type >= 2 || 2887ec681f3Smrg (This->actx->ref && This->actx->ref == This->screen)) 2897ec681f3Smrg has_present_buffers = TRUE; 2907ec681f3Smrg 2917ec681f3Smrg /* Note: the buffer depth has to match the window depth. 2927ec681f3Smrg * In practice, ARGB buffers can be used with windows 2937ec681f3Smrg * of depth 24. Windows of depth 32 are extremely rare. 2947ec681f3Smrg * So even if the buffer is ARGB, say it is depth 24. 2957ec681f3Smrg * It is common practice, for example that's how 2967ec681f3Smrg * glamor implements depth 24. 2977ec681f3Smrg * TODO: handle windows with other depths. Not possible in the short term. 2987ec681f3Smrg * For example 16 bits.*/ 2997ec681f3Smrg depth = 24; 3007ec681f3Smrg 3017ec681f3Smrg memset(&tmplt, 0, sizeof(tmplt)); 3027ec681f3Smrg tmplt.target = PIPE_TEXTURE_2D; 3037ec681f3Smrg tmplt.width0 = pParams->BackBufferWidth; 3047ec681f3Smrg tmplt.height0 = pParams->BackBufferHeight; 3057ec681f3Smrg tmplt.depth0 = 1; 3067ec681f3Smrg tmplt.last_level = 0; 3077ec681f3Smrg tmplt.array_size = 1; 3087ec681f3Smrg tmplt.usage = PIPE_USAGE_DEFAULT; 3097ec681f3Smrg tmplt.flags = 0; 3107ec681f3Smrg 3117ec681f3Smrg desc.Type = D3DRTYPE_SURFACE; 3127ec681f3Smrg desc.Pool = D3DPOOL_DEFAULT; 3137ec681f3Smrg desc.MultiSampleType = pParams->MultiSampleType; 3147ec681f3Smrg desc.MultiSampleQuality = pParams->MultiSampleQuality; 3157ec681f3Smrg desc.Width = pParams->BackBufferWidth; 3167ec681f3Smrg desc.Height = pParams->BackBufferHeight; 3177ec681f3Smrg 3187ec681f3Smrg for (i = 0; i < oldBufferCount; i++) { 3197ec681f3Smrg if (This->tasks[i]) 3207ec681f3Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i])); 3217ec681f3Smrg } 3227ec681f3Smrg memset(This->tasks, 0, sizeof(This->tasks)); 3237ec681f3Smrg 3247ec681f3Smrg if (This->pool) { 3257ec681f3Smrg _mesa_threadpool_destroy(This, This->pool); 3267ec681f3Smrg This->pool = NULL; 3277ec681f3Smrg } 3287ec681f3Smrg This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY); 3297ec681f3Smrg if (This->enable_threadpool) 3307ec681f3Smrg This->pool = _mesa_threadpool_create(This); 3317ec681f3Smrg if (!This->pool) 3327ec681f3Smrg This->enable_threadpool = FALSE; 3337ec681f3Smrg 3347ec681f3Smrg for (i = 0; i < oldBufferCount; i++) { 3357ec681f3Smrg D3DWindowBuffer_release(This, This->present_handles[i]); 3367ec681f3Smrg This->present_handles[i] = NULL; 3377ec681f3Smrg if (This->present_buffers[i]) 3387ec681f3Smrg pipe_resource_reference(&(This->present_buffers[i]), NULL); 3397ec681f3Smrg } 3407ec681f3Smrg 3417ec681f3Smrg if (newBufferCount != oldBufferCount) { 3427ec681f3Smrg for (i = newBufferCount; i < oldBufferCount; 3437ec681f3Smrg ++i) 3447ec681f3Smrg NineUnknown_Detach(NineUnknown(This->buffers[i])); 3457ec681f3Smrg 3467ec681f3Smrg for (i = oldBufferCount; i < newBufferCount; ++i) { 3477ec681f3Smrg This->buffers[i] = NULL; 3487ec681f3Smrg This->present_handles[i] = NULL; 3497ec681f3Smrg } 3507ec681f3Smrg } 3517ec681f3Smrg This->num_back_buffers = newBufferCount; 3527ec681f3Smrg 3537ec681f3Smrg for (i = 0; i < newBufferCount; ++i) { 3547ec681f3Smrg tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 3557ec681f3Smrg tmplt.nr_samples = multisample_type; 3567ec681f3Smrg tmplt.nr_storage_samples = multisample_type; 3577ec681f3Smrg if (!has_present_buffers) 3587ec681f3Smrg tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS; 3597ec681f3Smrg tmplt.format = d3d9_to_pipe_format_checked(This->screen, 3607ec681f3Smrg pParams->BackBufferFormat, 3617ec681f3Smrg PIPE_TEXTURE_2D, 3627ec681f3Smrg tmplt.nr_samples, 3637ec681f3Smrg tmplt.bind, FALSE, FALSE); 3647ec681f3Smrg if (tmplt.format == PIPE_FORMAT_NONE) 3657ec681f3Smrg return D3DERR_INVALIDCALL; 3667ec681f3Smrg resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt); 3677ec681f3Smrg if (!resource) { 3687ec681f3Smrg DBG("Failed to create pipe_resource.\n"); 3697ec681f3Smrg return D3DERR_OUTOFVIDEOMEMORY; 3707ec681f3Smrg } 3717ec681f3Smrg if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) 3727ec681f3Smrg resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; 3737ec681f3Smrg if (This->buffers[i]) { 3747ec681f3Smrg NineSurface9_SetMultiSampleType(This->buffers[i], desc.MultiSampleType); 3757ec681f3Smrg NineSurface9_SetResourceResize(This->buffers[i], resource); 3767ec681f3Smrg if (has_present_buffers) 3777ec681f3Smrg pipe_resource_reference(&resource, NULL); 3787ec681f3Smrg } else { 3797ec681f3Smrg desc.Format = pParams->BackBufferFormat; 3807ec681f3Smrg desc.Usage = D3DUSAGE_RENDERTARGET; 3817ec681f3Smrg hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0, 3827ec681f3Smrg 0, 0, &desc, &This->buffers[i]); 3837ec681f3Smrg if (has_present_buffers) 3847ec681f3Smrg pipe_resource_reference(&resource, NULL); 3857ec681f3Smrg if (FAILED(hr)) { 3867ec681f3Smrg DBG("Failed to create RT surface.\n"); 3877ec681f3Smrg return hr; 3887ec681f3Smrg } 3897ec681f3Smrg This->buffers[i]->base.base.forward = FALSE; 3907ec681f3Smrg } 3917ec681f3Smrg if (has_present_buffers) { 3927ec681f3Smrg tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; 3937ec681f3Smrg tmplt.bind = NINE_BIND_PRESENTBUFFER_FLAGS; 3947ec681f3Smrg tmplt.nr_samples = 0; 3957ec681f3Smrg tmplt.nr_storage_samples = 0; 3967ec681f3Smrg if (This->actx->linear_framebuffer) 3977ec681f3Smrg tmplt.bind |= PIPE_BIND_LINEAR; 3987ec681f3Smrg if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD) 3997ec681f3Smrg tmplt.bind |= PIPE_BIND_RENDER_TARGET; 4007ec681f3Smrg resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt); 4017ec681f3Smrg pipe_resource_reference(&(This->present_buffers[i]), resource); 4027ec681f3Smrg } 4037ec681f3Smrg This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth, false); 4047ec681f3Smrg pipe_resource_reference(&resource, NULL); 4057ec681f3Smrg if (!This->present_handles[i]) { 4067ec681f3Smrg return D3DERR_DRIVERINTERNALERROR; 4077ec681f3Smrg } 4087ec681f3Smrg } 4097ec681f3Smrg if (pParams->EnableAutoDepthStencil) { 4107ec681f3Smrg tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat); 4117ec681f3Smrg tmplt.nr_samples = multisample_type; 4127ec681f3Smrg tmplt.nr_storage_samples = multisample_type; 4137ec681f3Smrg tmplt.format = d3d9_to_pipe_format_checked(This->screen, 4147ec681f3Smrg pParams->AutoDepthStencilFormat, 4157ec681f3Smrg PIPE_TEXTURE_2D, 4167ec681f3Smrg tmplt.nr_samples, 4177ec681f3Smrg tmplt.bind, 4187ec681f3Smrg FALSE, FALSE); 4197ec681f3Smrg 4207ec681f3Smrg if (tmplt.format == PIPE_FORMAT_NONE) 4217ec681f3Smrg return D3DERR_INVALIDCALL; 4227ec681f3Smrg 4237ec681f3Smrg if (This->zsbuf) { 4247ec681f3Smrg resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt); 4257ec681f3Smrg if (!resource) { 4267ec681f3Smrg DBG("Failed to create pipe_resource for depth buffer.\n"); 4277ec681f3Smrg return D3DERR_OUTOFVIDEOMEMORY; 4287ec681f3Smrg } 4297ec681f3Smrg 4307ec681f3Smrg NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType); 4317ec681f3Smrg NineSurface9_SetResourceResize(This->zsbuf, resource); 4327ec681f3Smrg pipe_resource_reference(&resource, NULL); 4337ec681f3Smrg } else { 4347ec681f3Smrg hr = NineDevice9_CreateDepthStencilSurface(pDevice, 4357ec681f3Smrg pParams->BackBufferWidth, 4367ec681f3Smrg pParams->BackBufferHeight, 4377ec681f3Smrg pParams->AutoDepthStencilFormat, 4387ec681f3Smrg pParams->MultiSampleType, 4397ec681f3Smrg pParams->MultiSampleQuality, 4407ec681f3Smrg 0, 4417ec681f3Smrg (IDirect3DSurface9 **)&This->zsbuf, 4427ec681f3Smrg NULL); 4437ec681f3Smrg if (FAILED(hr)) { 4447ec681f3Smrg DBG("Failed to create ZS surface.\n"); 4457ec681f3Smrg return hr; 4467ec681f3Smrg } 4477ec681f3Smrg NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf)); 4487ec681f3Smrg } 4497ec681f3Smrg } 4507ec681f3Smrg 4517ec681f3Smrg This->params = *pParams; 4527ec681f3Smrg 4537ec681f3Smrg return D3D_OK; 4547ec681f3Smrg} 4557ec681f3Smrg 4567ec681f3Smrg/* Throttling: code adapted from the dri frontend */ 4577ec681f3Smrg 4587ec681f3Smrg/** 4597ec681f3Smrg * swap_fences_pop_front - pull a fence from the throttle queue 4607ec681f3Smrg * 4617ec681f3Smrg * If the throttle queue is filled to the desired number of fences, 4627ec681f3Smrg * pull fences off the queue until the number is less than the desired 4637ec681f3Smrg * number of fences, and return the last fence pulled. 4647ec681f3Smrg */ 4657ec681f3Smrgstatic struct pipe_fence_handle * 4667ec681f3Smrgswap_fences_pop_front(struct NineSwapChain9 *This) 4677ec681f3Smrg{ 4687ec681f3Smrg struct pipe_screen *screen = This->screen; 4697ec681f3Smrg struct pipe_fence_handle *fence = NULL; 4707ec681f3Smrg 4717ec681f3Smrg if (This->desired_fences == 0) 4727ec681f3Smrg return NULL; 4737ec681f3Smrg 4747ec681f3Smrg if (This->cur_fences >= This->desired_fences) { 4757ec681f3Smrg screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); 4767ec681f3Smrg screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); 4777ec681f3Smrg This->tail &= DRI_SWAP_FENCES_MASK; 4787ec681f3Smrg --This->cur_fences; 4797ec681f3Smrg } 4807ec681f3Smrg return fence; 4817ec681f3Smrg} 4827ec681f3Smrg 4837ec681f3Smrg 4847ec681f3Smrg/** 4857ec681f3Smrg * swap_fences_see_front - same than swap_fences_pop_front without 4867ec681f3Smrg * pulling 4877ec681f3Smrg * 4887ec681f3Smrg */ 4897ec681f3Smrg 4907ec681f3Smrgstatic struct pipe_fence_handle * 4917ec681f3Smrgswap_fences_see_front(struct NineSwapChain9 *This) 4927ec681f3Smrg{ 4937ec681f3Smrg struct pipe_screen *screen = This->screen; 4947ec681f3Smrg struct pipe_fence_handle *fence = NULL; 4957ec681f3Smrg 4967ec681f3Smrg if (This->desired_fences == 0) 4977ec681f3Smrg return NULL; 4987ec681f3Smrg 4997ec681f3Smrg if (This->cur_fences >= This->desired_fences) { 5007ec681f3Smrg screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); 5017ec681f3Smrg } 5027ec681f3Smrg return fence; 5037ec681f3Smrg} 5047ec681f3Smrg 5057ec681f3Smrg 5067ec681f3Smrg/** 5077ec681f3Smrg * swap_fences_push_back - push a fence onto the throttle queue at the back 5087ec681f3Smrg * 5097ec681f3Smrg * push a fence onto the throttle queue and pull fences of the queue 5107ec681f3Smrg * so that the desired number of fences are on the queue. 5117ec681f3Smrg */ 5127ec681f3Smrgstatic void 5137ec681f3Smrgswap_fences_push_back(struct NineSwapChain9 *This, 5147ec681f3Smrg struct pipe_fence_handle *fence) 5157ec681f3Smrg{ 5167ec681f3Smrg struct pipe_screen *screen = This->screen; 5177ec681f3Smrg 5187ec681f3Smrg if (!fence || This->desired_fences == 0) 5197ec681f3Smrg return; 5207ec681f3Smrg 5217ec681f3Smrg while(This->cur_fences == This->desired_fences) 5227ec681f3Smrg swap_fences_pop_front(This); 5237ec681f3Smrg 5247ec681f3Smrg This->cur_fences++; 5257ec681f3Smrg screen->fence_reference(screen, &This->swap_fences[This->head++], 5267ec681f3Smrg fence); 5277ec681f3Smrg This->head &= DRI_SWAP_FENCES_MASK; 5287ec681f3Smrg} 5297ec681f3Smrg 5307ec681f3Smrg 5317ec681f3Smrg/** 5327ec681f3Smrg * swap_fences_unref - empty the throttle queue 5337ec681f3Smrg * 5347ec681f3Smrg * pulls fences of the throttle queue until it is empty. 5357ec681f3Smrg */ 5367ec681f3Smrgstatic void 5377ec681f3Smrgswap_fences_unref(struct NineSwapChain9 *This) 5387ec681f3Smrg{ 5397ec681f3Smrg struct pipe_screen *screen = This->screen; 5407ec681f3Smrg 5417ec681f3Smrg while(This->cur_fences) { 5427ec681f3Smrg screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); 5437ec681f3Smrg This->tail &= DRI_SWAP_FENCES_MASK; 5447ec681f3Smrg --This->cur_fences; 5457ec681f3Smrg } 5467ec681f3Smrg} 5477ec681f3Smrg 5487ec681f3Smrgvoid 5497ec681f3SmrgNineSwapChain9_dtor( struct NineSwapChain9 *This ) 5507ec681f3Smrg{ 5517ec681f3Smrg unsigned i; 5527ec681f3Smrg 5537ec681f3Smrg DBG("This=%p\n", This); 5547ec681f3Smrg 5557ec681f3Smrg if (This->pool) 5567ec681f3Smrg _mesa_threadpool_destroy(This, This->pool); 5577ec681f3Smrg 5587ec681f3Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 5597ec681f3Smrg if (This->pending_presentation[i]) 5607ec681f3Smrg FREE(This->pending_presentation[i]); 5617ec681f3Smrg } 5627ec681f3Smrg 5637ec681f3Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 5647ec681f3Smrg if (This->present_handles_pending_release[i]) 5657ec681f3Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); 5667ec681f3Smrg } 5677ec681f3Smrg 5687ec681f3Smrg for (i = 0; i < This->num_back_buffers; i++) { 5697ec681f3Smrg if (This->buffers[i]) 5707ec681f3Smrg NineUnknown_Detach(NineUnknown(This->buffers[i])); 5717ec681f3Smrg if (This->present_handles[i]) 5727ec681f3Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); 5737ec681f3Smrg if (This->present_buffers[i]) 5747ec681f3Smrg pipe_resource_reference(&(This->present_buffers[i]), NULL); 5757ec681f3Smrg } 5767ec681f3Smrg if (This->zsbuf) 5777ec681f3Smrg NineUnknown_Unbind(NineUnknown(This->zsbuf)); 5787ec681f3Smrg 5797ec681f3Smrg if (This->present) 5807ec681f3Smrg ID3DPresent_Release(This->present); 5817ec681f3Smrg 5827ec681f3Smrg swap_fences_unref(This); 5837ec681f3Smrg NineUnknown_dtor(&This->base); 5847ec681f3Smrg} 5857ec681f3Smrg 5867ec681f3Smrgstatic void 5877ec681f3Smrgcreate_present_buffer( struct NineSwapChain9 *This, 5887ec681f3Smrg unsigned int width, unsigned int height, 5897ec681f3Smrg struct pipe_resource **resource, 5907ec681f3Smrg D3DWindowBuffer **present_handle) 5917ec681f3Smrg{ 5927ec681f3Smrg struct pipe_resource tmplt; 5937ec681f3Smrg 5947ec681f3Smrg memset(&tmplt, 0, sizeof(tmplt)); 5957ec681f3Smrg tmplt.target = PIPE_TEXTURE_2D; 5967ec681f3Smrg tmplt.width0 = width; 5977ec681f3Smrg tmplt.height0 = height; 5987ec681f3Smrg tmplt.depth0 = 1; 5997ec681f3Smrg tmplt.last_level = 0; 6007ec681f3Smrg tmplt.array_size = 1; 6017ec681f3Smrg tmplt.usage = PIPE_USAGE_DEFAULT; 6027ec681f3Smrg tmplt.flags = 0; 6037ec681f3Smrg tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; 6047ec681f3Smrg tmplt.bind = NINE_BIND_BACKBUFFER_FLAGS | 6057ec681f3Smrg NINE_BIND_PRESENTBUFFER_FLAGS; 6067ec681f3Smrg tmplt.nr_samples = 0; 6077ec681f3Smrg if (This->actx->linear_framebuffer) 6087ec681f3Smrg tmplt.bind |= PIPE_BIND_LINEAR; 6097ec681f3Smrg *resource = nine_resource_create_with_retry(This->base.device, This->screen, &tmplt); 6107ec681f3Smrg 6117ec681f3Smrg *present_handle = D3DWindowBuffer_create(This, *resource, 24, true); 6127ec681f3Smrg 6137ec681f3Smrg if (!*present_handle) { 6147ec681f3Smrg pipe_resource_reference(resource, NULL); 6157ec681f3Smrg } 6167ec681f3Smrg} 6177ec681f3Smrg 6187ec681f3Smrgstatic void 6197ec681f3Smrghandle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource) 6207ec681f3Smrg{ 6217ec681f3Smrg struct NineDevice9 *device = This->base.device; 6227ec681f3Smrg struct pipe_blit_info blit; 6237ec681f3Smrg struct pipe_context *pipe; 6247ec681f3Smrg 6257ec681f3Smrg if (device->cursor.software && device->cursor.visible && device->cursor.w) { 6267ec681f3Smrg memset(&blit, 0, sizeof(blit)); 6277ec681f3Smrg blit.src.resource = device->cursor.image; 6287ec681f3Smrg blit.src.level = 0; 6297ec681f3Smrg blit.src.format = device->cursor.image->format; 6307ec681f3Smrg blit.src.box.x = 0; 6317ec681f3Smrg blit.src.box.y = 0; 6327ec681f3Smrg blit.src.box.z = 0; 6337ec681f3Smrg blit.src.box.depth = 1; 6347ec681f3Smrg blit.src.box.width = device->cursor.w; 6357ec681f3Smrg blit.src.box.height = device->cursor.h; 6367ec681f3Smrg 6377ec681f3Smrg blit.dst.resource = resource; 6387ec681f3Smrg blit.dst.level = 0; 6397ec681f3Smrg blit.dst.format = resource->format; 6407ec681f3Smrg blit.dst.box.z = 0; 6417ec681f3Smrg blit.dst.box.depth = 1; 6427ec681f3Smrg 6437ec681f3Smrg blit.mask = PIPE_MASK_RGBA; 6447ec681f3Smrg blit.filter = PIPE_TEX_FILTER_NEAREST; 6457ec681f3Smrg blit.scissor_enable = FALSE; 6467ec681f3Smrg 6477ec681f3Smrg /* NOTE: blit messes up when box.x + box.width < 0, fix driver 6487ec681f3Smrg * NOTE2: device->cursor.pos contains coordinates relative to the screen. 6497ec681f3Smrg * This happens to be also the position of the cursor when we are fullscreen. 6507ec681f3Smrg * We don't use sw cursor for Windowed mode */ 6517ec681f3Smrg blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; 6527ec681f3Smrg blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; 6537ec681f3Smrg blit.dst.box.width = blit.src.box.width; 6547ec681f3Smrg blit.dst.box.height = blit.src.box.height; 6557ec681f3Smrg 6567ec681f3Smrg DBG("Blitting cursor(%ux%u) to (%i,%i).\n", 6577ec681f3Smrg blit.src.box.width, blit.src.box.height, 6587ec681f3Smrg blit.dst.box.x, blit.dst.box.y); 6597ec681f3Smrg 6607ec681f3Smrg blit.alpha_blend = TRUE; 6617ec681f3Smrg pipe = NineDevice9_GetPipe(This->base.device); 6627ec681f3Smrg pipe->blit(pipe, &blit); 6637ec681f3Smrg } 6647ec681f3Smrg 6657ec681f3Smrg if (device->hud && resource) { 6667ec681f3Smrg /* Implicit use of context pipe */ 6677ec681f3Smrg (void)NineDevice9_GetPipe(This->base.device); 6687ec681f3Smrg hud_run(device->hud, NULL, resource); /* XXX: no offset */ 6697ec681f3Smrg /* HUD doesn't clobber stipple */ 6707ec681f3Smrg nine_state_restore_non_cso(device); 6717ec681f3Smrg } 6727ec681f3Smrg} 6737ec681f3Smrg 6747ec681f3Smrgstruct end_present_struct { 6757ec681f3Smrg struct pipe_screen *screen; 6767ec681f3Smrg struct pipe_fence_handle *fence_to_wait; 6777ec681f3Smrg ID3DPresent *present; 6787ec681f3Smrg D3DWindowBuffer *present_handle; 6797ec681f3Smrg BOOL *pending_presentation; 6807ec681f3Smrg HWND hDestWindowOverride; 6817ec681f3Smrg}; 6827ec681f3Smrg 6837ec681f3Smrgstatic void work_present(void *data) 6847ec681f3Smrg{ 6857ec681f3Smrg struct end_present_struct *work = data; 6867ec681f3Smrg if (work->fence_to_wait) { 6877ec681f3Smrg (void) work->screen->fence_finish(work->screen, NULL, work->fence_to_wait, PIPE_TIMEOUT_INFINITE); 6887ec681f3Smrg work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL); 6897ec681f3Smrg } 6907ec681f3Smrg ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0); 6917ec681f3Smrg p_atomic_set(work->pending_presentation, FALSE); 6927ec681f3Smrg free(work); 6937ec681f3Smrg} 6947ec681f3Smrg 6957ec681f3Smrgstatic void pend_present(struct NineSwapChain9 *This, 6967ec681f3Smrg struct pipe_fence_handle *fence, 6977ec681f3Smrg HWND hDestWindowOverride) 6987ec681f3Smrg{ 6997ec681f3Smrg struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct)); 7007ec681f3Smrg 7017ec681f3Smrg work->screen = This->screen; 7027ec681f3Smrg This->screen->fence_reference(This->screen, &work->fence_to_wait, fence); 7037ec681f3Smrg work->present = This->present; 7047ec681f3Smrg work->present_handle = This->present_handles[0]; 7057ec681f3Smrg work->hDestWindowOverride = hDestWindowOverride; 7067ec681f3Smrg work->pending_presentation = This->pending_presentation[0]; 7077ec681f3Smrg p_atomic_set(work->pending_presentation, TRUE); 7087ec681f3Smrg This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work); 7097ec681f3Smrg 7107ec681f3Smrg return; 7117ec681f3Smrg} 7127ec681f3Smrg 7137ec681f3Smrgstatic inline HRESULT 7147ec681f3Smrgpresent( struct NineSwapChain9 *This, 7157ec681f3Smrg const RECT *pSourceRect, 7167ec681f3Smrg const RECT *pDestRect, 7177ec681f3Smrg HWND hDestWindowOverride, 7187ec681f3Smrg const RGNDATA *pDirtyRegion, 7197ec681f3Smrg DWORD dwFlags ) 7207ec681f3Smrg{ 7217ec681f3Smrg struct pipe_context *pipe; 7227ec681f3Smrg struct pipe_resource *resource; 7237ec681f3Smrg struct pipe_fence_handle *fence; 7247ec681f3Smrg HRESULT hr; 7257ec681f3Smrg struct pipe_blit_info blit; 7267ec681f3Smrg int target_width, target_height, target_depth, i; 7277ec681f3Smrg RECT source_rect; 7287ec681f3Smrg RECT dest_rect; 7297ec681f3Smrg 7307ec681f3Smrg DBG("present: This=%p pSourceRect=%p pDestRect=%p " 7317ec681f3Smrg "pDirtyRegion=%p hDestWindowOverride=%p" 7327ec681f3Smrg "dwFlags=%d resource=%p\n", 7337ec681f3Smrg This, pSourceRect, pDestRect, pDirtyRegion, 7347ec681f3Smrg hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource); 7357ec681f3Smrg 7367ec681f3Smrg /* We can choose to only update pDirtyRegion, but the backend can choose 7377ec681f3Smrg * to update everything. Let's ignore */ 7387ec681f3Smrg (void) pDirtyRegion; 7397ec681f3Smrg 7407ec681f3Smrg resource = This->buffers[0]->base.resource; 7417ec681f3Smrg 7427ec681f3Smrg if (pSourceRect) { 7437ec681f3Smrg DBG("pSourceRect = (%u..%u)x(%u..%u)\n", 7447ec681f3Smrg pSourceRect->left, pSourceRect->right, 7457ec681f3Smrg pSourceRect->top, pSourceRect->bottom); 7467ec681f3Smrg source_rect = *pSourceRect; 7477ec681f3Smrg if (source_rect.top == 0 && 7487ec681f3Smrg source_rect.left == 0 && 7497ec681f3Smrg source_rect.bottom == resource->height0 && 7507ec681f3Smrg source_rect.right == resource->width0) 7517ec681f3Smrg pSourceRect = NULL; 7527ec681f3Smrg /* TODO: Handle more of pSourceRect. 7537ec681f3Smrg * Currently we should support: 7547ec681f3Smrg * . When there is no pSourceRect 7557ec681f3Smrg * . When pSourceRect is the full buffer. 7567ec681f3Smrg */ 7577ec681f3Smrg } 7587ec681f3Smrg if (pDestRect) { 7597ec681f3Smrg DBG("pDestRect = (%u..%u)x(%u..%u)\n", 7607ec681f3Smrg pDestRect->left, pDestRect->right, 7617ec681f3Smrg pDestRect->top, pDestRect->bottom); 7627ec681f3Smrg dest_rect = *pDestRect; 7637ec681f3Smrg } 7647ec681f3Smrg 7657ec681f3Smrg if (This->rendering_done) 7667ec681f3Smrg goto bypass_rendering; 7677ec681f3Smrg 7687ec681f3Smrg if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD) 7697ec681f3Smrg handle_draw_cursor_and_hud(This, resource); 7707ec681f3Smrg 7717ec681f3Smrg hr = ID3DPresent_GetWindowInfo(This->present, hDestWindowOverride, &target_width, &target_height, &target_depth); 7727ec681f3Smrg (void)target_depth; 7737ec681f3Smrg 7747ec681f3Smrg /* Can happen with old Wine (presentation can still succeed), 7757ec681f3Smrg * or at window destruction. 7767ec681f3Smrg * Also disable for very old wine as D3DWindowBuffer_release 7777ec681f3Smrg * cannot do the DestroyD3DWindowBuffer workaround. */ 7787ec681f3Smrg if (FAILED(hr) || target_width == 0 || target_height == 0 || 7797ec681f3Smrg This->base.device->minor_version_num <= 2) { 7807ec681f3Smrg target_width = resource->width0; 7817ec681f3Smrg target_height = resource->height0; 7827ec681f3Smrg } 7837ec681f3Smrg 7847ec681f3Smrg if (pDestRect) { 7857ec681f3Smrg dest_rect.top = MAX2(0, dest_rect.top); 7867ec681f3Smrg dest_rect.left = MAX2(0, dest_rect.left); 7877ec681f3Smrg dest_rect.bottom = MIN2(target_height, dest_rect.bottom); 7887ec681f3Smrg dest_rect.right = MIN2(target_width, dest_rect.right); 7897ec681f3Smrg target_height = dest_rect.bottom - dest_rect.top; 7907ec681f3Smrg target_width = dest_rect.right - dest_rect.left; 7917ec681f3Smrg } 7927ec681f3Smrg 7937ec681f3Smrg /* Switch to using presentation buffers on window resize. 7947ec681f3Smrg * Note: Most apps should resize the d3d back buffers when 7957ec681f3Smrg * a window resize is detected, which will result in a call to 7967ec681f3Smrg * NineSwapChain9_Resize. Thus everything will get released, 7977ec681f3Smrg * and it will switch back to not using separate presentation 7987ec681f3Smrg * buffers. */ 7997ec681f3Smrg if (!This->present_buffers[0] && 8007ec681f3Smrg (target_width != resource->width0 || target_height != resource->height0)) { 8017ec681f3Smrg BOOL failure = false; 8027ec681f3Smrg struct pipe_resource *new_resource[This->num_back_buffers]; 8037ec681f3Smrg D3DWindowBuffer *new_handles[This->num_back_buffers]; 8047ec681f3Smrg for (i = 0; i < This->num_back_buffers; i++) { 8057ec681f3Smrg /* Note: if (!new_handles[i]), new_resource[i] 8067ec681f3Smrg * gets released and contains NULL */ 8077ec681f3Smrg create_present_buffer(This, target_width, target_height, &new_resource[i], &new_handles[i]); 8087ec681f3Smrg if (!new_handles[i]) 8097ec681f3Smrg failure = true; 8107ec681f3Smrg } 8117ec681f3Smrg if (failure) { 8127ec681f3Smrg for (i = 0; i < This->num_back_buffers; i++) { 8137ec681f3Smrg if (new_resource[i]) 8147ec681f3Smrg pipe_resource_reference(&new_resource[i], NULL); 8157ec681f3Smrg if (new_handles[i]) 8167ec681f3Smrg D3DWindowBuffer_release(This, new_handles[i]); 8177ec681f3Smrg } 8187ec681f3Smrg } else { 8197ec681f3Smrg for (i = 0; i < This->num_back_buffers; i++) { 8207ec681f3Smrg D3DWindowBuffer_release(This, This->present_handles[i]); 8217ec681f3Smrg This->present_handles[i] = new_handles[i]; 8227ec681f3Smrg pipe_resource_reference(&This->present_buffers[i], new_resource[i]); 8237ec681f3Smrg pipe_resource_reference(&new_resource[i], NULL); 8247ec681f3Smrg } 8257ec681f3Smrg } 8267ec681f3Smrg } 8277ec681f3Smrg 8287ec681f3Smrg pipe = NineDevice9_GetPipe(This->base.device); 8297ec681f3Smrg 8307ec681f3Smrg if (This->present_buffers[0]) { 8317ec681f3Smrg memset(&blit, 0, sizeof(blit)); 8327ec681f3Smrg blit.src.resource = resource; 8337ec681f3Smrg blit.src.level = 0; /* Note: This->buffers[0]->level should always be 0 */ 8347ec681f3Smrg blit.src.format = resource->format; 8357ec681f3Smrg blit.src.box.z = 0; 8367ec681f3Smrg blit.src.box.depth = 1; 8377ec681f3Smrg blit.src.box.x = 0; 8387ec681f3Smrg blit.src.box.y = 0; 8397ec681f3Smrg blit.src.box.width = resource->width0; 8407ec681f3Smrg blit.src.box.height = resource->height0; 8417ec681f3Smrg 8427ec681f3Smrg /* Reallocate a new presentation buffer if the target window 8437ec681f3Smrg * size has changed */ 8447ec681f3Smrg if (target_width != This->present_buffers[0]->width0 || 8457ec681f3Smrg target_height != This->present_buffers[0]->height0) { 8467ec681f3Smrg struct pipe_resource *new_resource; 8477ec681f3Smrg D3DWindowBuffer *new_handle; 8487ec681f3Smrg 8497ec681f3Smrg create_present_buffer(This, target_width, target_height, &new_resource, &new_handle); 8507ec681f3Smrg /* Switch to the new buffer */ 8517ec681f3Smrg if (new_handle) { 8527ec681f3Smrg D3DWindowBuffer_release(This, This->present_handles[0]); 8537ec681f3Smrg This->present_handles[0] = new_handle; 8547ec681f3Smrg pipe_resource_reference(&This->present_buffers[0], new_resource); 8557ec681f3Smrg pipe_resource_reference(&new_resource, NULL); 8567ec681f3Smrg } 8577ec681f3Smrg } 8587ec681f3Smrg 8597ec681f3Smrg resource = This->present_buffers[0]; 8607ec681f3Smrg 8617ec681f3Smrg blit.dst.resource = resource; 8627ec681f3Smrg blit.dst.level = 0; 8637ec681f3Smrg blit.dst.format = resource->format; 8647ec681f3Smrg blit.dst.box.z = 0; 8657ec681f3Smrg blit.dst.box.depth = 1; 8667ec681f3Smrg blit.dst.box.x = 0; 8677ec681f3Smrg blit.dst.box.y = 0; 8687ec681f3Smrg blit.dst.box.width = resource->width0; 8697ec681f3Smrg blit.dst.box.height = resource->height0; 8707ec681f3Smrg 8717ec681f3Smrg blit.mask = PIPE_MASK_RGBA; 8727ec681f3Smrg blit.filter = (blit.dst.box.width == blit.src.box.width && 8737ec681f3Smrg blit.dst.box.height == blit.src.box.height) ? 8747ec681f3Smrg PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; 8757ec681f3Smrg blit.scissor_enable = FALSE; 8767ec681f3Smrg blit.alpha_blend = FALSE; 8777ec681f3Smrg 8787ec681f3Smrg pipe->blit(pipe, &blit); 8797ec681f3Smrg } 8807ec681f3Smrg 8817ec681f3Smrg /* The resource we present has to resolve fast clears 8827ec681f3Smrg * if needed (and other things) */ 8837ec681f3Smrg pipe->flush_resource(pipe, resource); 8847ec681f3Smrg 8857ec681f3Smrg if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD) 8867ec681f3Smrg handle_draw_cursor_and_hud(This, resource); 8877ec681f3Smrg 8887ec681f3Smrg fence = NULL; 8897ec681f3Smrg /* When threadpool is enabled, we don't submit before the fence 8907ec681f3Smrg * tells us rendering was finished, thus we can flush async there */ 8917ec681f3Smrg pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME | (This->enable_threadpool ? PIPE_FLUSH_ASYNC : 0)); 8927ec681f3Smrg 8937ec681f3Smrg /* Present now for thread_submit, because we have the fence. 8947ec681f3Smrg * It's possible we return WASSTILLDRAWING and still Present, 8957ec681f3Smrg * but it should be fine. */ 8967ec681f3Smrg if (This->enable_threadpool) 8977ec681f3Smrg pend_present(This, fence, hDestWindowOverride); 8987ec681f3Smrg if (fence) { 8997ec681f3Smrg swap_fences_push_back(This, fence); 9007ec681f3Smrg This->screen->fence_reference(This->screen, &fence, NULL); 9017ec681f3Smrg } 9027ec681f3Smrg 9037ec681f3Smrg This->rendering_done = TRUE; 9047ec681f3Smrgbypass_rendering: 9057ec681f3Smrg 9067ec681f3Smrg if (dwFlags & D3DPRESENT_DONOTWAIT) { 9077ec681f3Smrg UNTESTED(2); 9087ec681f3Smrg BOOL still_draw = FALSE; 9097ec681f3Smrg fence = swap_fences_see_front(This); 9107ec681f3Smrg if (fence) { 9117ec681f3Smrg still_draw = !This->screen->fence_finish(This->screen, NULL, fence, 0); 9127ec681f3Smrg This->screen->fence_reference(This->screen, &fence, NULL); 9137ec681f3Smrg } 9147ec681f3Smrg if (still_draw) 9157ec681f3Smrg return D3DERR_WASSTILLDRAWING; 9167ec681f3Smrg } 9177ec681f3Smrg 9187ec681f3Smrg /* Throttle rendering if needed */ 9197ec681f3Smrg fence = swap_fences_pop_front(This); 9207ec681f3Smrg if (fence) { 9217ec681f3Smrg (void) This->screen->fence_finish(This->screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 9227ec681f3Smrg This->screen->fence_reference(This->screen, &fence, NULL); 9237ec681f3Smrg } 9247ec681f3Smrg 9257ec681f3Smrg This->rendering_done = FALSE; 9267ec681f3Smrg 9277ec681f3Smrg if (!This->enable_threadpool) { 9287ec681f3Smrg This->tasks[0]=NULL; 9297ec681f3Smrg 9307ec681f3Smrg hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect ? &dest_rect : NULL, NULL, dwFlags); 9317ec681f3Smrg 9327ec681f3Smrg if (FAILED(hr)) { UNTESTED(3);return hr; } 9337ec681f3Smrg } 9347ec681f3Smrg 9357ec681f3Smrg This->base.device->end_scene_since_present = 0; 9367ec681f3Smrg This->base.device->frame_count++; 9377ec681f3Smrg return D3D_OK; 9387ec681f3Smrg} 9397ec681f3Smrg 9407ec681f3SmrgHRESULT NINE_WINAPI 9417ec681f3SmrgNineSwapChain9_Present( struct NineSwapChain9 *This, 9427ec681f3Smrg const RECT *pSourceRect, 9437ec681f3Smrg const RECT *pDestRect, 9447ec681f3Smrg HWND hDestWindowOverride, 9457ec681f3Smrg const RGNDATA *pDirtyRegion, 9467ec681f3Smrg DWORD dwFlags ) 9477ec681f3Smrg{ 9487ec681f3Smrg struct pipe_resource *res = NULL; 9497ec681f3Smrg D3DWindowBuffer *handle_temp; 9507ec681f3Smrg struct threadpool_task *task_temp; 9517ec681f3Smrg BOOL *pending_presentation_temp; 9527ec681f3Smrg int i; 9537ec681f3Smrg HRESULT hr; 9547ec681f3Smrg 9557ec681f3Smrg DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " 9567ec681f3Smrg "pDirtyRegion=%p dwFlags=%d\n", 9577ec681f3Smrg This, pSourceRect, pDestRect, hDestWindowOverride, 9587ec681f3Smrg pDirtyRegion,dwFlags); 9597ec681f3Smrg 9607ec681f3Smrg if (This->base.device->ex) { 9617ec681f3Smrg if (NineSwapChain9_GetOccluded(This)) { 9627ec681f3Smrg DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n"); 9637ec681f3Smrg return S_PRESENT_OCCLUDED; 9647ec681f3Smrg } 9657ec681f3Smrg } else { 9667ec681f3Smrg if (NineSwapChain9_GetOccluded(This) || 9677ec681f3Smrg NineSwapChain9_ResolutionMismatch(This)) { 9687ec681f3Smrg This->base.device->device_needs_reset = TRUE; 9697ec681f3Smrg } 9707ec681f3Smrg if (This->base.device->device_needs_reset) { 9717ec681f3Smrg DBG("Device is lost. Returning D3DERR_DEVICELOST.\n"); 9727ec681f3Smrg return D3DERR_DEVICELOST; 9737ec681f3Smrg } 9747ec681f3Smrg } 9757ec681f3Smrg 9767ec681f3Smrg nine_csmt_process(This->base.device); 9777ec681f3Smrg 9787ec681f3Smrg hr = present(This, pSourceRect, pDestRect, 9797ec681f3Smrg hDestWindowOverride, pDirtyRegion, dwFlags); 9807ec681f3Smrg if (hr == D3DERR_WASSTILLDRAWING) 9817ec681f3Smrg return hr; 9827ec681f3Smrg 9837ec681f3Smrg if (This->base.device->minor_version_num > 2 && 9847ec681f3Smrg This->actx->discard_delayed_release && 9857ec681f3Smrg This->params.SwapEffect == D3DSWAPEFFECT_DISCARD && 9867ec681f3Smrg This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { 9877ec681f3Smrg int next_buffer = -1; 9887ec681f3Smrg 9897ec681f3Smrg while (next_buffer == -1) { 9907ec681f3Smrg /* Find a free backbuffer */ 9917ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) { 9927ec681f3Smrg if (!p_atomic_read(This->pending_presentation[i]) && 9937ec681f3Smrg ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) { 9947ec681f3Smrg DBG("Found buffer released: %d\n", i); 9957ec681f3Smrg next_buffer = i; 9967ec681f3Smrg break; 9977ec681f3Smrg } 9987ec681f3Smrg } 9997ec681f3Smrg if (next_buffer == -1) { 10007ec681f3Smrg DBG("Found no buffer released. Waiting for event\n"); 10017ec681f3Smrg ID3DPresent_WaitBufferReleaseEvent(This->present); 10027ec681f3Smrg } 10037ec681f3Smrg } 10047ec681f3Smrg 10057ec681f3Smrg /* Free the task (we already checked it is finished) */ 10067ec681f3Smrg if (This->tasks[next_buffer]) 10077ec681f3Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[next_buffer])); 10087ec681f3Smrg assert(!*This->pending_presentation[next_buffer] && !This->tasks[next_buffer]); 10097ec681f3Smrg This->tasks[next_buffer] = This->tasks[0]; 10107ec681f3Smrg This->tasks[0] = NULL; 10117ec681f3Smrg pending_presentation_temp = This->pending_presentation[next_buffer]; 10127ec681f3Smrg This->pending_presentation[next_buffer] = This->pending_presentation[0]; 10137ec681f3Smrg This->pending_presentation[0] = pending_presentation_temp; 10147ec681f3Smrg 10157ec681f3Smrg /* Switch with the released buffer */ 10167ec681f3Smrg pipe_resource_reference(&res, This->buffers[0]->base.resource); 10177ec681f3Smrg NineSurface9_SetResourceResize( 10187ec681f3Smrg This->buffers[0], This->buffers[next_buffer]->base.resource); 10197ec681f3Smrg NineSurface9_SetResourceResize( 10207ec681f3Smrg This->buffers[next_buffer], res); 10217ec681f3Smrg pipe_resource_reference(&res, NULL); 10227ec681f3Smrg 10237ec681f3Smrg if (This->present_buffers[0]) { 10247ec681f3Smrg pipe_resource_reference(&res, This->present_buffers[0]); 10257ec681f3Smrg pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]); 10267ec681f3Smrg pipe_resource_reference(&This->present_buffers[next_buffer], res); 10277ec681f3Smrg pipe_resource_reference(&res, NULL); 10287ec681f3Smrg } 10297ec681f3Smrg 10307ec681f3Smrg handle_temp = This->present_handles[0]; 10317ec681f3Smrg This->present_handles[0] = This->present_handles[next_buffer]; 10327ec681f3Smrg This->present_handles[next_buffer] = handle_temp; 10337ec681f3Smrg } else { 10347ec681f3Smrg switch (This->params.SwapEffect) { 10357ec681f3Smrg case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */ 10367ec681f3Smrg case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */ 10377ec681f3Smrg case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */ 10387ec681f3Smrg case D3DSWAPEFFECT_FLIP: 10397ec681f3Smrg /* rotate the queue */ 10407ec681f3Smrg pipe_resource_reference(&res, This->buffers[0]->base.resource); 10417ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) { 10427ec681f3Smrg NineSurface9_SetResourceResize(This->buffers[i - 1], 10437ec681f3Smrg This->buffers[i]->base.resource); 10447ec681f3Smrg } 10457ec681f3Smrg NineSurface9_SetResourceResize( 10467ec681f3Smrg This->buffers[This->num_back_buffers - 1], res); 10477ec681f3Smrg pipe_resource_reference(&res, NULL); 10487ec681f3Smrg 10497ec681f3Smrg if (This->present_buffers[0]) { 10507ec681f3Smrg pipe_resource_reference(&res, This->present_buffers[0]); 10517ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) 10527ec681f3Smrg pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); 10537ec681f3Smrg pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); 10547ec681f3Smrg pipe_resource_reference(&res, NULL); 10557ec681f3Smrg } 10567ec681f3Smrg 10577ec681f3Smrg handle_temp = This->present_handles[0]; 10587ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) { 10597ec681f3Smrg This->present_handles[i-1] = This->present_handles[i]; 10607ec681f3Smrg } 10617ec681f3Smrg This->present_handles[This->num_back_buffers - 1] = handle_temp; 10627ec681f3Smrg task_temp = This->tasks[0]; 10637ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) { 10647ec681f3Smrg This->tasks[i-1] = This->tasks[i]; 10657ec681f3Smrg } 10667ec681f3Smrg This->tasks[This->num_back_buffers - 1] = task_temp; 10677ec681f3Smrg pending_presentation_temp = This->pending_presentation[0]; 10687ec681f3Smrg for (i = 1; i < This->num_back_buffers; i++) { 10697ec681f3Smrg This->pending_presentation[i-1] = This->pending_presentation[i]; 10707ec681f3Smrg } 10717ec681f3Smrg This->pending_presentation[This->num_back_buffers - 1] = pending_presentation_temp; 10727ec681f3Smrg break; 10737ec681f3Smrg 10747ec681f3Smrg case D3DSWAPEFFECT_COPY: 10757ec681f3Smrg /* do nothing */ 10767ec681f3Smrg break; 10777ec681f3Smrg } 10787ec681f3Smrg 10797ec681f3Smrg if (This->tasks[0]) 10807ec681f3Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); 10817ec681f3Smrg assert(!*This->pending_presentation[0]); 10827ec681f3Smrg 10837ec681f3Smrg ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); 10847ec681f3Smrg } 10857ec681f3Smrg 10867ec681f3Smrg This->base.device->context.changed.group |= NINE_STATE_FB; 10877ec681f3Smrg 10887ec681f3Smrg return hr; 10897ec681f3Smrg} 10907ec681f3Smrg 10917ec681f3SmrgHRESULT NINE_WINAPI 10927ec681f3SmrgNineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, 10937ec681f3Smrg IDirect3DSurface9 *pDestSurface ) 10947ec681f3Smrg{ 10957ec681f3Smrg struct NineSurface9 *dest_surface = NineSurface9(pDestSurface); 10967ec681f3Smrg struct NineDevice9 *pDevice = This->base.device; 10977ec681f3Smrg unsigned int width, height; 10987ec681f3Smrg struct pipe_resource *temp_resource; 10997ec681f3Smrg struct NineSurface9 *temp_surface; 11007ec681f3Smrg D3DWindowBuffer *temp_handle; 11017ec681f3Smrg D3DSURFACE_DESC desc; 11027ec681f3Smrg HRESULT hr; 11037ec681f3Smrg 11047ec681f3Smrg DBG("GetFrontBufferData: This=%p pDestSurface=%p\n", 11057ec681f3Smrg This, pDestSurface); 11067ec681f3Smrg 11077ec681f3Smrg user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); 11087ec681f3Smrg 11097ec681f3Smrg width = dest_surface->desc.Width; 11107ec681f3Smrg height = dest_surface->desc.Height; 11117ec681f3Smrg 11127ec681f3Smrg /* Note: front window size and destination size are supposed 11137ec681f3Smrg * to match. However it's not very clear what should get taken in Windowed 11147ec681f3Smrg * mode. It may need a fix */ 11157ec681f3Smrg create_present_buffer(This, width, height, &temp_resource, &temp_handle); 11167ec681f3Smrg 11177ec681f3Smrg if (!temp_resource || !temp_handle) { 11187ec681f3Smrg return D3DERR_INVALIDCALL; 11197ec681f3Smrg } 11207ec681f3Smrg 11217ec681f3Smrg desc.Type = D3DRTYPE_SURFACE; 11227ec681f3Smrg desc.Pool = D3DPOOL_DEFAULT; 11237ec681f3Smrg desc.MultiSampleType = D3DMULTISAMPLE_NONE; 11247ec681f3Smrg desc.MultiSampleQuality = 0; 11257ec681f3Smrg desc.Width = width; 11267ec681f3Smrg desc.Height = height; 11277ec681f3Smrg /* NineSurface9_CopyDefaultToMem needs same format. */ 11287ec681f3Smrg desc.Format = dest_surface->desc.Format; 11297ec681f3Smrg desc.Usage = D3DUSAGE_RENDERTARGET; 11307ec681f3Smrg hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0, 11317ec681f3Smrg 0, 0, &desc, &temp_surface); 11327ec681f3Smrg pipe_resource_reference(&temp_resource, NULL); 11337ec681f3Smrg if (FAILED(hr)) { 11347ec681f3Smrg DBG("Failed to create temp FrontBuffer surface.\n"); 11357ec681f3Smrg return hr; 11367ec681f3Smrg } 11377ec681f3Smrg 11387ec681f3Smrg ID3DPresent_FrontBufferCopy(This->present, temp_handle); 11397ec681f3Smrg 11407ec681f3Smrg NineSurface9_CopyDefaultToMem(dest_surface, temp_surface); 11417ec681f3Smrg 11427ec681f3Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); 11437ec681f3Smrg NineUnknown_Destroy(NineUnknown(temp_surface)); 11447ec681f3Smrg 11457ec681f3Smrg return D3D_OK; 11467ec681f3Smrg} 11477ec681f3Smrg 11487ec681f3SmrgHRESULT NINE_WINAPI 11497ec681f3SmrgNineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, 11507ec681f3Smrg UINT iBackBuffer, 11517ec681f3Smrg D3DBACKBUFFER_TYPE Type, 11527ec681f3Smrg IDirect3DSurface9 **ppBackBuffer ) 11537ec681f3Smrg{ 11547ec681f3Smrg DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n", 11557ec681f3Smrg This, iBackBuffer, Type, ppBackBuffer); 11567ec681f3Smrg (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO); 11577ec681f3Smrg /* don't touch ppBackBuffer on error */ 11587ec681f3Smrg user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL); 11597ec681f3Smrg user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL); 11607ec681f3Smrg 11617ec681f3Smrg NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer])); 11627ec681f3Smrg *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer]; 11637ec681f3Smrg return D3D_OK; 11647ec681f3Smrg} 11657ec681f3Smrg 11667ec681f3SmrgHRESULT NINE_WINAPI 11677ec681f3SmrgNineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, 11687ec681f3Smrg D3DRASTER_STATUS *pRasterStatus ) 11697ec681f3Smrg{ 11707ec681f3Smrg DBG("GetRasterStatus: This=%p pRasterStatus=%p\n", 11717ec681f3Smrg This, pRasterStatus); 11727ec681f3Smrg user_assert(pRasterStatus != NULL, E_POINTER); 11737ec681f3Smrg return ID3DPresent_GetRasterStatus(This->present, pRasterStatus); 11747ec681f3Smrg} 11757ec681f3Smrg 11767ec681f3SmrgHRESULT NINE_WINAPI 11777ec681f3SmrgNineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, 11787ec681f3Smrg D3DDISPLAYMODE *pMode ) 11797ec681f3Smrg{ 11807ec681f3Smrg D3DDISPLAYMODEEX mode; 11817ec681f3Smrg D3DDISPLAYROTATION rot; 11827ec681f3Smrg HRESULT hr; 11837ec681f3Smrg 11847ec681f3Smrg DBG("GetDisplayMode: This=%p pMode=%p\n", 11857ec681f3Smrg This, pMode); 11867ec681f3Smrg user_assert(pMode != NULL, E_POINTER); 11877ec681f3Smrg 11887ec681f3Smrg hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot); 11897ec681f3Smrg if (SUCCEEDED(hr)) { 11907ec681f3Smrg pMode->Width = mode.Width; 11917ec681f3Smrg pMode->Height = mode.Height; 11927ec681f3Smrg pMode->RefreshRate = mode.RefreshRate; 11937ec681f3Smrg pMode->Format = mode.Format; 11947ec681f3Smrg } 11957ec681f3Smrg return hr; 11967ec681f3Smrg} 11977ec681f3Smrg 11987ec681f3SmrgHRESULT NINE_WINAPI 11997ec681f3SmrgNineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, 12007ec681f3Smrg D3DPRESENT_PARAMETERS *pPresentationParameters ) 12017ec681f3Smrg{ 12027ec681f3Smrg DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n", 12037ec681f3Smrg This, pPresentationParameters); 12047ec681f3Smrg user_assert(pPresentationParameters != NULL, E_POINTER); 12057ec681f3Smrg *pPresentationParameters = This->params; 12067ec681f3Smrg return D3D_OK; 12077ec681f3Smrg} 12087ec681f3Smrg 12097ec681f3SmrgIDirect3DSwapChain9Vtbl NineSwapChain9_vtable = { 12107ec681f3Smrg (void *)NineUnknown_QueryInterface, 12117ec681f3Smrg (void *)NineUnknown_AddRef, 12127ec681f3Smrg (void *)NineUnknown_Release, 12137ec681f3Smrg (void *)NineSwapChain9_Present, 12147ec681f3Smrg (void *)NineSwapChain9_GetFrontBufferData, 12157ec681f3Smrg (void *)NineSwapChain9_GetBackBuffer, 12167ec681f3Smrg (void *)NineSwapChain9_GetRasterStatus, 12177ec681f3Smrg (void *)NineSwapChain9_GetDisplayMode, 12187ec681f3Smrg (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */ 12197ec681f3Smrg (void *)NineSwapChain9_GetPresentParameters 12207ec681f3Smrg}; 12217ec681f3Smrg 12227ec681f3Smrgstatic const GUID *NineSwapChain9_IIDs[] = { 12237ec681f3Smrg &IID_IDirect3DSwapChain9, 12247ec681f3Smrg &IID_IUnknown, 12257ec681f3Smrg NULL 12267ec681f3Smrg}; 12277ec681f3Smrg 12287ec681f3SmrgHRESULT 12297ec681f3SmrgNineSwapChain9_new( struct NineDevice9 *pDevice, 12307ec681f3Smrg BOOL implicit, 12317ec681f3Smrg ID3DPresent *pPresent, 12327ec681f3Smrg D3DPRESENT_PARAMETERS *pPresentationParameters, 12337ec681f3Smrg struct d3dadapter9_context *pCTX, 12347ec681f3Smrg HWND hFocusWindow, 12357ec681f3Smrg struct NineSwapChain9 **ppOut ) 12367ec681f3Smrg{ 12377ec681f3Smrg NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */ 12387ec681f3Smrg implicit, pPresent, pPresentationParameters, 12397ec681f3Smrg pCTX, hFocusWindow, NULL); 12407ec681f3Smrg} 12417ec681f3Smrg 12427ec681f3SmrgBOOL 12437ec681f3SmrgNineSwapChain9_GetOccluded( struct NineSwapChain9 *This ) 12447ec681f3Smrg{ 12457ec681f3Smrg if (This->base.device->minor_version_num > 0) { 12467ec681f3Smrg return ID3DPresent_GetWindowOccluded(This->present); 12477ec681f3Smrg } 12487ec681f3Smrg 12497ec681f3Smrg return FALSE; 12507ec681f3Smrg} 12517ec681f3Smrg 12527ec681f3SmrgBOOL 12537ec681f3SmrgNineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This ) 12547ec681f3Smrg{ 12557ec681f3Smrg if (This->base.device->minor_version_num > 1) { 12567ec681f3Smrg return ID3DPresent_ResolutionMismatch(This->present); 12577ec681f3Smrg } 12587ec681f3Smrg 12597ec681f3Smrg return FALSE; 12607ec681f3Smrg} 12617ec681f3Smrg 12627ec681f3SmrgHANDLE 12637ec681f3SmrgNineSwapChain9_CreateThread( struct NineSwapChain9 *This, 12647ec681f3Smrg void *pFuncAddress, 12657ec681f3Smrg void *pParam ) 12667ec681f3Smrg{ 12677ec681f3Smrg if (This->base.device->minor_version_num > 1) { 12687ec681f3Smrg return ID3DPresent_CreateThread(This->present, pFuncAddress, pParam); 12697ec681f3Smrg } 12707ec681f3Smrg 12717ec681f3Smrg return NULL; 12727ec681f3Smrg} 12737ec681f3Smrg 12747ec681f3Smrgvoid 12757ec681f3SmrgNineSwapChain9_WaitForThread( struct NineSwapChain9 *This, 12767ec681f3Smrg HANDLE thread ) 12777ec681f3Smrg{ 12787ec681f3Smrg if (This->base.device->minor_version_num > 1) { 12797ec681f3Smrg (void) ID3DPresent_WaitForThread(This->present, thread); 12807ec681f3Smrg } 12817ec681f3Smrg} 12827ec681f3Smrg 12837ec681f3Smrgstatic int 12847ec681f3SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, 12857ec681f3Smrg D3DPRESENT_PARAMETERS *pParams ) 12867ec681f3Smrg{ 12877ec681f3Smrg int count = pParams->BackBufferCount; 12887ec681f3Smrg 12897ec681f3Smrg /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. 12907ec681f3Smrg * Here we don't get back the initial content of the screen. To emulate the behaviour 12917ec681f3Smrg * we allocate an additional buffer */ 12927ec681f3Smrg if (pParams->SwapEffect != D3DSWAPEFFECT_COPY) 12937ec681f3Smrg count++; 12947ec681f3Smrg /* With DISCARD, as there is no guarantee about the buffer contents, we can use 12957ec681f3Smrg * an arbitrary number of buffers */ 12967ec681f3Smrg if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) { 12977ec681f3Smrg /* thread_submit's can have maximum count or This->actx->throttling_value + 1 12987ec681f3Smrg * frames in flight being rendered and not shown. 12997ec681f3Smrg * Do not let count decrease that number */ 13007ec681f3Smrg if (This->actx->thread_submit && count < This->desired_fences) 13017ec681f3Smrg count = This->desired_fences; 13027ec681f3Smrg /* When we enable AllowDISCARDDelayedRelease, we must ensure 13037ec681f3Smrg * to have at least 4 buffers to meet INTERVAL_IMMEDIATE, 13047ec681f3Smrg * since the display server/compositor can hold 3 buffers 13057ec681f3Smrg * without releasing them: 13067ec681f3Smrg * . Buffer on screen. 13077ec681f3Smrg * . Buffer scheduled kernel side to be next on screen. 13087ec681f3Smrg * . Last buffer sent. */ 13097ec681f3Smrg if (This->base.device->minor_version_num > 2 && 13107ec681f3Smrg This->actx->discard_delayed_release && 13117ec681f3Smrg pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { 13127ec681f3Smrg if (This->actx->thread_submit && count < 4) 13137ec681f3Smrg count = 4; 13147ec681f3Smrg /* When thread_submit is not used, 5 buffers are actually needed, 13157ec681f3Smrg * because in case a pageflip is missed because rendering wasn't finished, 13167ec681f3Smrg * the Xserver will hold 4 buffers. */ 13177ec681f3Smrg else if (!This->actx->thread_submit && count < 5) 13187ec681f3Smrg count = 5; 13197ec681f3Smrg /* Somehow this cases needs 5 with thread_submit, or else you get a small performance hit */ 13207ec681f3Smrg if (This->actx->tearfree_discard && count < 5) 13217ec681f3Smrg count = 5; 13227ec681f3Smrg } 13237ec681f3Smrg } 13247ec681f3Smrg 13257ec681f3Smrg return count; 13267ec681f3Smrg} 1327