1b8e80941Smrg/* 2b8e80941Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8b8e80941Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9b8e80941Smrg * the Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19b8e80941Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20b8e80941Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21b8e80941Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */ 22b8e80941Smrg 23b8e80941Smrg#include "swapchain9.h" 24b8e80941Smrg#include "surface9.h" 25b8e80941Smrg#include "device9.h" 26b8e80941Smrg 27b8e80941Smrg#include "nine_helpers.h" 28b8e80941Smrg#include "nine_pipe.h" 29b8e80941Smrg#include "nine_dump.h" 30b8e80941Smrg 31b8e80941Smrg#include "util/u_atomic.h" 32b8e80941Smrg#include "util/u_inlines.h" 33b8e80941Smrg#include "util/u_surface.h" 34b8e80941Smrg#include "hud/hud_context.h" 35b8e80941Smrg#include "state_tracker/drm_driver.h" 36b8e80941Smrg 37b8e80941Smrg#include "threadpool.h" 38b8e80941Smrg 39b8e80941Smrg#define DBG_CHANNEL DBG_SWAPCHAIN 40b8e80941Smrg 41b8e80941Smrg#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n) 42b8e80941Smrg 43b8e80941SmrgHRESULT 44b8e80941SmrgNineSwapChain9_ctor( struct NineSwapChain9 *This, 45b8e80941Smrg struct NineUnknownParams *pParams, 46b8e80941Smrg BOOL implicit, 47b8e80941Smrg ID3DPresent *pPresent, 48b8e80941Smrg D3DPRESENT_PARAMETERS *pPresentationParameters, 49b8e80941Smrg struct d3dadapter9_context *pCTX, 50b8e80941Smrg HWND hFocusWindow, 51b8e80941Smrg D3DDISPLAYMODEEX *mode ) 52b8e80941Smrg{ 53b8e80941Smrg HRESULT hr; 54b8e80941Smrg int i; 55b8e80941Smrg 56b8e80941Smrg DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n", 57b8e80941Smrg This, pParams->device, pPresent, pCTX, hFocusWindow); 58b8e80941Smrg 59b8e80941Smrg hr = NineUnknown_ctor(&This->base, pParams); 60b8e80941Smrg if (FAILED(hr)) 61b8e80941Smrg return hr; 62b8e80941Smrg 63b8e80941Smrg This->screen = NineDevice9_GetScreen(This->base.device); 64b8e80941Smrg This->implicit = implicit; 65b8e80941Smrg This->actx = pCTX; 66b8e80941Smrg This->present = pPresent; 67b8e80941Smrg This->mode = NULL; 68b8e80941Smrg 69b8e80941Smrg ID3DPresent_AddRef(pPresent); 70b8e80941Smrg if (This->base.device->minor_version_num > 2) { 71b8e80941Smrg D3DPRESENT_PARAMETERS2 params2; 72b8e80941Smrg 73b8e80941Smrg memset(¶ms2, 0, sizeof(D3DPRESENT_PARAMETERS2)); 74b8e80941Smrg params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release; 75b8e80941Smrg params2.TearFreeDISCARD = This->actx->tearfree_discard; 76b8e80941Smrg ID3DPresent_SetPresentParameters2(pPresent, ¶ms2); 77b8e80941Smrg } 78b8e80941Smrg 79b8e80941Smrg if (!pPresentationParameters->hDeviceWindow) 80b8e80941Smrg pPresentationParameters->hDeviceWindow = hFocusWindow; 81b8e80941Smrg 82b8e80941Smrg This->rendering_done = FALSE; 83b8e80941Smrg This->pool = NULL; 84b8e80941Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 85b8e80941Smrg This->pending_presentation[i] = calloc(1, sizeof(BOOL)); 86b8e80941Smrg if (!This->pending_presentation[i]) 87b8e80941Smrg return E_OUTOFMEMORY; 88b8e80941Smrg } 89b8e80941Smrg return NineSwapChain9_Resize(This, pPresentationParameters, mode); 90b8e80941Smrg} 91b8e80941Smrg 92b8e80941Smrgstatic D3DWindowBuffer * 93b8e80941SmrgD3DWindowBuffer_create(struct NineSwapChain9 *This, 94b8e80941Smrg struct pipe_resource *resource, 95b8e80941Smrg int depth, 96b8e80941Smrg int for_frontbuffer_reading) 97b8e80941Smrg{ 98b8e80941Smrg D3DWindowBuffer *ret; 99b8e80941Smrg struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device); 100b8e80941Smrg struct winsys_handle whandle; 101b8e80941Smrg int stride, dmaBufFd; 102b8e80941Smrg HRESULT hr; 103b8e80941Smrg 104b8e80941Smrg memset(&whandle, 0, sizeof(whandle)); 105b8e80941Smrg whandle.type = WINSYS_HANDLE_TYPE_FD; 106b8e80941Smrg This->screen->resource_get_handle(This->screen, pipe, resource, 107b8e80941Smrg &whandle, 108b8e80941Smrg for_frontbuffer_reading ? 109b8e80941Smrg PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE : 110b8e80941Smrg PIPE_HANDLE_USAGE_EXPLICIT_FLUSH); 111b8e80941Smrg nine_context_get_pipe_release(This->base.device); 112b8e80941Smrg stride = whandle.stride; 113b8e80941Smrg dmaBufFd = whandle.handle; 114b8e80941Smrg hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present, 115b8e80941Smrg dmaBufFd, 116b8e80941Smrg resource->width0, 117b8e80941Smrg resource->height0, 118b8e80941Smrg stride, 119b8e80941Smrg depth, 120b8e80941Smrg 32, 121b8e80941Smrg &ret); 122b8e80941Smrg assert (SUCCEEDED(hr)); 123b8e80941Smrg 124b8e80941Smrg if (FAILED(hr)) { 125b8e80941Smrg ERR("Failed to create new D3DWindowBufferFromDmaBuf\n"); 126b8e80941Smrg return NULL; 127b8e80941Smrg } 128b8e80941Smrg return ret; 129b8e80941Smrg} 130b8e80941Smrg 131b8e80941Smrgstatic void 132b8e80941SmrgD3DWindowBuffer_release(struct NineSwapChain9 *This, 133b8e80941Smrg D3DWindowBuffer *present_handle) 134b8e80941Smrg{ 135b8e80941Smrg int i; 136b8e80941Smrg 137b8e80941Smrg /* IsBufferReleased API not available */ 138b8e80941Smrg if (This->base.device->minor_version_num <= 2) { 139b8e80941Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, present_handle); 140b8e80941Smrg return; 141b8e80941Smrg } 142b8e80941Smrg 143b8e80941Smrg /* Add it to the 'pending release' list */ 144b8e80941Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 145b8e80941Smrg if (!This->present_handles_pending_release[i]) { 146b8e80941Smrg This->present_handles_pending_release[i] = present_handle; 147b8e80941Smrg break; 148b8e80941Smrg } 149b8e80941Smrg } 150b8e80941Smrg if (i == (D3DPRESENT_BACK_BUFFERS_MAX_EX + 1)) { 151b8e80941Smrg ERR("Server not releasing buffers...\n"); 152b8e80941Smrg assert(false); 153b8e80941Smrg } 154b8e80941Smrg 155b8e80941Smrg /* Destroy elements of the list released by the server */ 156b8e80941Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 157b8e80941Smrg if (This->present_handles_pending_release[i] && 158b8e80941Smrg ID3DPresent_IsBufferReleased(This->present, This->present_handles_pending_release[i])) { 159b8e80941Smrg /* WaitBufferReleased also waits the presentation feedback 160b8e80941Smrg * (which should arrive at about the same time), 161b8e80941Smrg * while IsBufferReleased doesn't. DestroyD3DWindowBuffer unfortunately 162b8e80941Smrg * checks it to release immediately all data, else the release 163b8e80941Smrg * is postponed for This->present release. To avoid leaks (we may handle 164b8e80941Smrg * a lot of resize), call WaitBufferReleased. */ 165b8e80941Smrg ID3DPresent_WaitBufferReleased(This->present, This->present_handles_pending_release[i]); 166b8e80941Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); 167b8e80941Smrg This->present_handles_pending_release[i] = NULL; 168b8e80941Smrg } 169b8e80941Smrg } 170b8e80941Smrg} 171b8e80941Smrg 172b8e80941Smrgstatic int 173b8e80941SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, 174b8e80941Smrg D3DPRESENT_PARAMETERS *pParams ); 175b8e80941Smrg 176b8e80941SmrgHRESULT 177b8e80941SmrgNineSwapChain9_Resize( struct NineSwapChain9 *This, 178b8e80941Smrg D3DPRESENT_PARAMETERS *pParams, 179b8e80941Smrg D3DDISPLAYMODEEX *mode ) 180b8e80941Smrg{ 181b8e80941Smrg struct NineDevice9 *pDevice = This->base.device; 182b8e80941Smrg D3DSURFACE_DESC desc; 183b8e80941Smrg HRESULT hr; 184b8e80941Smrg struct pipe_resource *resource, tmplt; 185b8e80941Smrg enum pipe_format pf; 186b8e80941Smrg BOOL has_present_buffers = FALSE; 187b8e80941Smrg int depth; 188b8e80941Smrg unsigned i, oldBufferCount, newBufferCount; 189b8e80941Smrg D3DMULTISAMPLE_TYPE multisample_type; 190b8e80941Smrg 191b8e80941Smrg DBG("This=%p pParams=%p\n", This, pParams); 192b8e80941Smrg user_assert(pParams != NULL, E_POINTER); 193b8e80941Smrg user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL); 194b8e80941Smrg user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) || 195b8e80941Smrg (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL); 196b8e80941Smrg user_assert(pDevice->ex || pParams->BackBufferCount <= 197b8e80941Smrg D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL); 198b8e80941Smrg user_assert(!pDevice->ex || pParams->BackBufferCount <= 199b8e80941Smrg D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL); 200b8e80941Smrg user_assert(pDevice->ex || 201b8e80941Smrg (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) || 202b8e80941Smrg (pParams->SwapEffect == D3DSWAPEFFECT_COPY) || 203b8e80941Smrg (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL); 204b8e80941Smrg 205b8e80941Smrg DBG("pParams(%p):\n" 206b8e80941Smrg "BackBufferWidth: %u\n" 207b8e80941Smrg "BackBufferHeight: %u\n" 208b8e80941Smrg "BackBufferFormat: %s\n" 209b8e80941Smrg "BackBufferCount: %u\n" 210b8e80941Smrg "MultiSampleType: %u\n" 211b8e80941Smrg "MultiSampleQuality: %u\n" 212b8e80941Smrg "SwapEffect: %u\n" 213b8e80941Smrg "hDeviceWindow: %p\n" 214b8e80941Smrg "Windowed: %i\n" 215b8e80941Smrg "EnableAutoDepthStencil: %i\n" 216b8e80941Smrg "AutoDepthStencilFormat: %s\n" 217b8e80941Smrg "Flags: %s\n" 218b8e80941Smrg "FullScreen_RefreshRateInHz: %u\n" 219b8e80941Smrg "PresentationInterval: %x\n", pParams, 220b8e80941Smrg pParams->BackBufferWidth, pParams->BackBufferHeight, 221b8e80941Smrg d3dformat_to_string(pParams->BackBufferFormat), 222b8e80941Smrg pParams->BackBufferCount, 223b8e80941Smrg pParams->MultiSampleType, pParams->MultiSampleQuality, 224b8e80941Smrg pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed, 225b8e80941Smrg pParams->EnableAutoDepthStencil, 226b8e80941Smrg d3dformat_to_string(pParams->AutoDepthStencilFormat), 227b8e80941Smrg nine_D3DPRESENTFLAG_to_str(pParams->Flags), 228b8e80941Smrg pParams->FullScreen_RefreshRateInHz, 229b8e80941Smrg pParams->PresentationInterval); 230b8e80941Smrg 231b8e80941Smrg if (pParams->BackBufferCount == 0) { 232b8e80941Smrg pParams->BackBufferCount = 1; 233b8e80941Smrg } 234b8e80941Smrg 235b8e80941Smrg if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) { 236b8e80941Smrg pParams->BackBufferFormat = D3DFMT_A8R8G8B8; 237b8e80941Smrg } 238b8e80941Smrg 239b8e80941Smrg This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0; 240b8e80941Smrg /* +1 because we add the fence of the current buffer before popping an old one */ 241b8e80941Smrg if (This->desired_fences > DRI_SWAP_FENCES_MAX) 242b8e80941Smrg This->desired_fences = DRI_SWAP_FENCES_MAX; 243b8e80941Smrg 244b8e80941Smrg if (This->actx->vblank_mode == 0) 245b8e80941Smrg pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 246b8e80941Smrg else if (This->actx->vblank_mode == 3) 247b8e80941Smrg pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE; 248b8e80941Smrg 249b8e80941Smrg if (mode && This->mode) { 250b8e80941Smrg *(This->mode) = *mode; 251b8e80941Smrg } else if (mode) { 252b8e80941Smrg This->mode = malloc(sizeof(D3DDISPLAYMODEEX)); 253b8e80941Smrg memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX)); 254b8e80941Smrg } else { 255b8e80941Smrg free(This->mode); 256b8e80941Smrg This->mode = NULL; 257b8e80941Smrg } 258b8e80941Smrg 259b8e80941Smrg /* Note: It is the role of the backend to fill if necessary 260b8e80941Smrg * BackBufferWidth and BackBufferHeight */ 261b8e80941Smrg hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); 262b8e80941Smrg if (hr != D3D_OK) 263b8e80941Smrg return hr; 264b8e80941Smrg 265b8e80941Smrg oldBufferCount = This->num_back_buffers; 266b8e80941Smrg newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams); 267b8e80941Smrg 268b8e80941Smrg multisample_type = pParams->MultiSampleType; 269b8e80941Smrg 270b8e80941Smrg /* Map MultiSampleQuality to MultiSampleType */ 271b8e80941Smrg hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat, 272b8e80941Smrg &multisample_type, 273b8e80941Smrg pParams->MultiSampleQuality, 274b8e80941Smrg NULL); 275b8e80941Smrg if (FAILED(hr)) { 276b8e80941Smrg return hr; 277b8e80941Smrg } 278b8e80941Smrg 279b8e80941Smrg pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat, 280b8e80941Smrg PIPE_TEXTURE_2D, multisample_type, 281b8e80941Smrg PIPE_BIND_RENDER_TARGET, FALSE, FALSE); 282b8e80941Smrg 283b8e80941Smrg if (This->actx->linear_framebuffer || 284b8e80941Smrg (pf != PIPE_FORMAT_B8G8R8X8_UNORM && 285b8e80941Smrg pf != PIPE_FORMAT_B8G8R8A8_UNORM) || 286b8e80941Smrg pParams->SwapEffect != D3DSWAPEFFECT_DISCARD || 287b8e80941Smrg multisample_type >= 2 || 288b8e80941Smrg (This->actx->ref && This->actx->ref == This->screen)) 289b8e80941Smrg has_present_buffers = TRUE; 290b8e80941Smrg 291b8e80941Smrg /* Note: the buffer depth has to match the window depth. 292b8e80941Smrg * In practice, ARGB buffers can be used with windows 293b8e80941Smrg * of depth 24. Windows of depth 32 are extremely rare. 294b8e80941Smrg * So even if the buffer is ARGB, say it is depth 24. 295b8e80941Smrg * It is common practice, for example that's how 296b8e80941Smrg * glamor implements depth 24. 297b8e80941Smrg * TODO: handle windows with other depths. Not possible in the short term. 298b8e80941Smrg * For example 16 bits.*/ 299b8e80941Smrg depth = 24; 300b8e80941Smrg 301b8e80941Smrg memset(&tmplt, 0, sizeof(tmplt)); 302b8e80941Smrg tmplt.target = PIPE_TEXTURE_2D; 303b8e80941Smrg tmplt.width0 = pParams->BackBufferWidth; 304b8e80941Smrg tmplt.height0 = pParams->BackBufferHeight; 305b8e80941Smrg tmplt.depth0 = 1; 306b8e80941Smrg tmplt.last_level = 0; 307b8e80941Smrg tmplt.array_size = 1; 308b8e80941Smrg tmplt.usage = PIPE_USAGE_DEFAULT; 309b8e80941Smrg tmplt.flags = 0; 310b8e80941Smrg 311b8e80941Smrg desc.Type = D3DRTYPE_SURFACE; 312b8e80941Smrg desc.Pool = D3DPOOL_DEFAULT; 313b8e80941Smrg desc.MultiSampleType = pParams->MultiSampleType; 314b8e80941Smrg desc.MultiSampleQuality = pParams->MultiSampleQuality; 315b8e80941Smrg desc.Width = pParams->BackBufferWidth; 316b8e80941Smrg desc.Height = pParams->BackBufferHeight; 317b8e80941Smrg 318b8e80941Smrg for (i = 0; i < oldBufferCount; i++) { 319b8e80941Smrg if (This->tasks[i]) 320b8e80941Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i])); 321b8e80941Smrg } 322b8e80941Smrg memset(This->tasks, 0, sizeof(This->tasks)); 323b8e80941Smrg 324b8e80941Smrg if (This->pool) { 325b8e80941Smrg _mesa_threadpool_destroy(This, This->pool); 326b8e80941Smrg This->pool = NULL; 327b8e80941Smrg } 328b8e80941Smrg This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY); 329b8e80941Smrg if (This->enable_threadpool) 330b8e80941Smrg This->pool = _mesa_threadpool_create(This); 331b8e80941Smrg if (!This->pool) 332b8e80941Smrg This->enable_threadpool = FALSE; 333b8e80941Smrg 334b8e80941Smrg for (i = 0; i < oldBufferCount; i++) { 335b8e80941Smrg D3DWindowBuffer_release(This, This->present_handles[i]); 336b8e80941Smrg This->present_handles[i] = NULL; 337b8e80941Smrg if (This->present_buffers[i]) 338b8e80941Smrg pipe_resource_reference(&(This->present_buffers[i]), NULL); 339b8e80941Smrg } 340b8e80941Smrg 341b8e80941Smrg if (newBufferCount != oldBufferCount) { 342b8e80941Smrg for (i = newBufferCount; i < oldBufferCount; 343b8e80941Smrg ++i) 344b8e80941Smrg NineUnknown_Detach(NineUnknown(This->buffers[i])); 345b8e80941Smrg 346b8e80941Smrg for (i = oldBufferCount; i < newBufferCount; ++i) { 347b8e80941Smrg This->buffers[i] = NULL; 348b8e80941Smrg This->present_handles[i] = NULL; 349b8e80941Smrg } 350b8e80941Smrg } 351b8e80941Smrg This->num_back_buffers = newBufferCount; 352b8e80941Smrg 353b8e80941Smrg for (i = 0; i < newBufferCount; ++i) { 354b8e80941Smrg tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 355b8e80941Smrg tmplt.nr_samples = multisample_type; 356b8e80941Smrg tmplt.nr_storage_samples = multisample_type; 357b8e80941Smrg if (!has_present_buffers) 358b8e80941Smrg tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS; 359b8e80941Smrg tmplt.format = d3d9_to_pipe_format_checked(This->screen, 360b8e80941Smrg pParams->BackBufferFormat, 361b8e80941Smrg PIPE_TEXTURE_2D, 362b8e80941Smrg tmplt.nr_samples, 363b8e80941Smrg tmplt.bind, FALSE, FALSE); 364b8e80941Smrg if (tmplt.format == PIPE_FORMAT_NONE) 365b8e80941Smrg return D3DERR_INVALIDCALL; 366b8e80941Smrg resource = This->screen->resource_create(This->screen, &tmplt); 367b8e80941Smrg if (!resource) { 368b8e80941Smrg DBG("Failed to create pipe_resource.\n"); 369b8e80941Smrg return D3DERR_OUTOFVIDEOMEMORY; 370b8e80941Smrg } 371b8e80941Smrg if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) 372b8e80941Smrg resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE; 373b8e80941Smrg if (This->buffers[i]) { 374b8e80941Smrg NineSurface9_SetMultiSampleType(This->buffers[i], desc.MultiSampleType); 375b8e80941Smrg NineSurface9_SetResourceResize(This->buffers[i], resource); 376b8e80941Smrg if (has_present_buffers) 377b8e80941Smrg pipe_resource_reference(&resource, NULL); 378b8e80941Smrg } else { 379b8e80941Smrg desc.Format = pParams->BackBufferFormat; 380b8e80941Smrg desc.Usage = D3DUSAGE_RENDERTARGET; 381b8e80941Smrg hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0, 382b8e80941Smrg 0, 0, &desc, &This->buffers[i]); 383b8e80941Smrg if (has_present_buffers) 384b8e80941Smrg pipe_resource_reference(&resource, NULL); 385b8e80941Smrg if (FAILED(hr)) { 386b8e80941Smrg DBG("Failed to create RT surface.\n"); 387b8e80941Smrg return hr; 388b8e80941Smrg } 389b8e80941Smrg This->buffers[i]->base.base.forward = FALSE; 390b8e80941Smrg } 391b8e80941Smrg if (has_present_buffers) { 392b8e80941Smrg tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; 393b8e80941Smrg tmplt.bind = NINE_BIND_PRESENTBUFFER_FLAGS; 394b8e80941Smrg tmplt.nr_samples = 0; 395b8e80941Smrg tmplt.nr_storage_samples = 0; 396b8e80941Smrg if (This->actx->linear_framebuffer) 397b8e80941Smrg tmplt.bind |= PIPE_BIND_LINEAR; 398b8e80941Smrg if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD) 399b8e80941Smrg tmplt.bind |= PIPE_BIND_RENDER_TARGET; 400b8e80941Smrg resource = This->screen->resource_create(This->screen, &tmplt); 401b8e80941Smrg pipe_resource_reference(&(This->present_buffers[i]), resource); 402b8e80941Smrg } 403b8e80941Smrg This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth, false); 404b8e80941Smrg pipe_resource_reference(&resource, NULL); 405b8e80941Smrg if (!This->present_handles[i]) { 406b8e80941Smrg return D3DERR_DRIVERINTERNALERROR; 407b8e80941Smrg } 408b8e80941Smrg } 409b8e80941Smrg if (pParams->EnableAutoDepthStencil) { 410b8e80941Smrg tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat); 411b8e80941Smrg tmplt.nr_samples = multisample_type; 412b8e80941Smrg tmplt.nr_storage_samples = multisample_type; 413b8e80941Smrg tmplt.format = d3d9_to_pipe_format_checked(This->screen, 414b8e80941Smrg pParams->AutoDepthStencilFormat, 415b8e80941Smrg PIPE_TEXTURE_2D, 416b8e80941Smrg tmplt.nr_samples, 417b8e80941Smrg tmplt.bind, 418b8e80941Smrg FALSE, FALSE); 419b8e80941Smrg 420b8e80941Smrg if (tmplt.format == PIPE_FORMAT_NONE) 421b8e80941Smrg return D3DERR_INVALIDCALL; 422b8e80941Smrg 423b8e80941Smrg if (This->zsbuf) { 424b8e80941Smrg resource = This->screen->resource_create(This->screen, &tmplt); 425b8e80941Smrg if (!resource) { 426b8e80941Smrg DBG("Failed to create pipe_resource for depth buffer.\n"); 427b8e80941Smrg return D3DERR_OUTOFVIDEOMEMORY; 428b8e80941Smrg } 429b8e80941Smrg 430b8e80941Smrg NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType); 431b8e80941Smrg NineSurface9_SetResourceResize(This->zsbuf, resource); 432b8e80941Smrg pipe_resource_reference(&resource, NULL); 433b8e80941Smrg } else { 434b8e80941Smrg hr = NineDevice9_CreateDepthStencilSurface(pDevice, 435b8e80941Smrg pParams->BackBufferWidth, 436b8e80941Smrg pParams->BackBufferHeight, 437b8e80941Smrg pParams->AutoDepthStencilFormat, 438b8e80941Smrg pParams->MultiSampleType, 439b8e80941Smrg pParams->MultiSampleQuality, 440b8e80941Smrg 0, 441b8e80941Smrg (IDirect3DSurface9 **)&This->zsbuf, 442b8e80941Smrg NULL); 443b8e80941Smrg if (FAILED(hr)) { 444b8e80941Smrg DBG("Failed to create ZS surface.\n"); 445b8e80941Smrg return hr; 446b8e80941Smrg } 447b8e80941Smrg NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf)); 448b8e80941Smrg } 449b8e80941Smrg } 450b8e80941Smrg 451b8e80941Smrg This->params = *pParams; 452b8e80941Smrg 453b8e80941Smrg return D3D_OK; 454b8e80941Smrg} 455b8e80941Smrg 456b8e80941Smrg/* Throttling: code adapted from the dri state tracker */ 457b8e80941Smrg 458b8e80941Smrg/** 459b8e80941Smrg * swap_fences_pop_front - pull a fence from the throttle queue 460b8e80941Smrg * 461b8e80941Smrg * If the throttle queue is filled to the desired number of fences, 462b8e80941Smrg * pull fences off the queue until the number is less than the desired 463b8e80941Smrg * number of fences, and return the last fence pulled. 464b8e80941Smrg */ 465b8e80941Smrgstatic struct pipe_fence_handle * 466b8e80941Smrgswap_fences_pop_front(struct NineSwapChain9 *This) 467b8e80941Smrg{ 468b8e80941Smrg struct pipe_screen *screen = This->screen; 469b8e80941Smrg struct pipe_fence_handle *fence = NULL; 470b8e80941Smrg 471b8e80941Smrg if (This->desired_fences == 0) 472b8e80941Smrg return NULL; 473b8e80941Smrg 474b8e80941Smrg if (This->cur_fences >= This->desired_fences) { 475b8e80941Smrg screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); 476b8e80941Smrg screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); 477b8e80941Smrg This->tail &= DRI_SWAP_FENCES_MASK; 478b8e80941Smrg --This->cur_fences; 479b8e80941Smrg } 480b8e80941Smrg return fence; 481b8e80941Smrg} 482b8e80941Smrg 483b8e80941Smrg 484b8e80941Smrg/** 485b8e80941Smrg * swap_fences_see_front - same than swap_fences_pop_front without 486b8e80941Smrg * pulling 487b8e80941Smrg * 488b8e80941Smrg */ 489b8e80941Smrg 490b8e80941Smrgstatic struct pipe_fence_handle * 491b8e80941Smrgswap_fences_see_front(struct NineSwapChain9 *This) 492b8e80941Smrg{ 493b8e80941Smrg struct pipe_screen *screen = This->screen; 494b8e80941Smrg struct pipe_fence_handle *fence = NULL; 495b8e80941Smrg 496b8e80941Smrg if (This->desired_fences == 0) 497b8e80941Smrg return NULL; 498b8e80941Smrg 499b8e80941Smrg if (This->cur_fences >= This->desired_fences) { 500b8e80941Smrg screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); 501b8e80941Smrg } 502b8e80941Smrg return fence; 503b8e80941Smrg} 504b8e80941Smrg 505b8e80941Smrg 506b8e80941Smrg/** 507b8e80941Smrg * swap_fences_push_back - push a fence onto the throttle queue at the back 508b8e80941Smrg * 509b8e80941Smrg * push a fence onto the throttle queue and pull fences of the queue 510b8e80941Smrg * so that the desired number of fences are on the queue. 511b8e80941Smrg */ 512b8e80941Smrgstatic void 513b8e80941Smrgswap_fences_push_back(struct NineSwapChain9 *This, 514b8e80941Smrg struct pipe_fence_handle *fence) 515b8e80941Smrg{ 516b8e80941Smrg struct pipe_screen *screen = This->screen; 517b8e80941Smrg 518b8e80941Smrg if (!fence || This->desired_fences == 0) 519b8e80941Smrg return; 520b8e80941Smrg 521b8e80941Smrg while(This->cur_fences == This->desired_fences) 522b8e80941Smrg swap_fences_pop_front(This); 523b8e80941Smrg 524b8e80941Smrg This->cur_fences++; 525b8e80941Smrg screen->fence_reference(screen, &This->swap_fences[This->head++], 526b8e80941Smrg fence); 527b8e80941Smrg This->head &= DRI_SWAP_FENCES_MASK; 528b8e80941Smrg} 529b8e80941Smrg 530b8e80941Smrg 531b8e80941Smrg/** 532b8e80941Smrg * swap_fences_unref - empty the throttle queue 533b8e80941Smrg * 534b8e80941Smrg * pulls fences of the throttle queue until it is empty. 535b8e80941Smrg */ 536b8e80941Smrgstatic void 537b8e80941Smrgswap_fences_unref(struct NineSwapChain9 *This) 538b8e80941Smrg{ 539b8e80941Smrg struct pipe_screen *screen = This->screen; 540b8e80941Smrg 541b8e80941Smrg while(This->cur_fences) { 542b8e80941Smrg screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); 543b8e80941Smrg This->tail &= DRI_SWAP_FENCES_MASK; 544b8e80941Smrg --This->cur_fences; 545b8e80941Smrg } 546b8e80941Smrg} 547b8e80941Smrg 548b8e80941Smrgvoid 549b8e80941SmrgNineSwapChain9_dtor( struct NineSwapChain9 *This ) 550b8e80941Smrg{ 551b8e80941Smrg unsigned i; 552b8e80941Smrg 553b8e80941Smrg DBG("This=%p\n", This); 554b8e80941Smrg 555b8e80941Smrg if (This->pool) 556b8e80941Smrg _mesa_threadpool_destroy(This, This->pool); 557b8e80941Smrg 558b8e80941Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 559b8e80941Smrg if (This->pending_presentation[i]) 560b8e80941Smrg FREE(This->pending_presentation[i]); 561b8e80941Smrg } 562b8e80941Smrg 563b8e80941Smrg for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) { 564b8e80941Smrg if (This->present_handles_pending_release[i]) 565b8e80941Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]); 566b8e80941Smrg } 567b8e80941Smrg 568b8e80941Smrg for (i = 0; i < This->num_back_buffers; i++) { 569b8e80941Smrg if (This->buffers[i]) 570b8e80941Smrg NineUnknown_Detach(NineUnknown(This->buffers[i])); 571b8e80941Smrg if (This->present_handles[i]) 572b8e80941Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); 573b8e80941Smrg if (This->present_buffers[i]) 574b8e80941Smrg pipe_resource_reference(&(This->present_buffers[i]), NULL); 575b8e80941Smrg } 576b8e80941Smrg if (This->zsbuf) 577b8e80941Smrg NineUnknown_Unbind(NineUnknown(This->zsbuf)); 578b8e80941Smrg 579b8e80941Smrg if (This->present) 580b8e80941Smrg ID3DPresent_Release(This->present); 581b8e80941Smrg 582b8e80941Smrg swap_fences_unref(This); 583b8e80941Smrg NineUnknown_dtor(&This->base); 584b8e80941Smrg} 585b8e80941Smrg 586b8e80941Smrgstatic void 587b8e80941Smrgcreate_present_buffer( struct NineSwapChain9 *This, 588b8e80941Smrg unsigned int width, unsigned int height, 589b8e80941Smrg struct pipe_resource **resource, 590b8e80941Smrg D3DWindowBuffer **present_handle) 591b8e80941Smrg{ 592b8e80941Smrg struct pipe_resource tmplt; 593b8e80941Smrg 594b8e80941Smrg memset(&tmplt, 0, sizeof(tmplt)); 595b8e80941Smrg tmplt.target = PIPE_TEXTURE_2D; 596b8e80941Smrg tmplt.width0 = width; 597b8e80941Smrg tmplt.height0 = height; 598b8e80941Smrg tmplt.depth0 = 1; 599b8e80941Smrg tmplt.last_level = 0; 600b8e80941Smrg tmplt.array_size = 1; 601b8e80941Smrg tmplt.usage = PIPE_USAGE_DEFAULT; 602b8e80941Smrg tmplt.flags = 0; 603b8e80941Smrg tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; 604b8e80941Smrg tmplt.bind = NINE_BIND_BACKBUFFER_FLAGS | 605b8e80941Smrg NINE_BIND_PRESENTBUFFER_FLAGS; 606b8e80941Smrg tmplt.nr_samples = 0; 607b8e80941Smrg if (This->actx->linear_framebuffer) 608b8e80941Smrg tmplt.bind |= PIPE_BIND_LINEAR; 609b8e80941Smrg *resource = This->screen->resource_create(This->screen, &tmplt); 610b8e80941Smrg 611b8e80941Smrg *present_handle = D3DWindowBuffer_create(This, *resource, 24, true); 612b8e80941Smrg 613b8e80941Smrg if (!*present_handle) { 614b8e80941Smrg pipe_resource_reference(resource, NULL); 615b8e80941Smrg } 616b8e80941Smrg} 617b8e80941Smrg 618b8e80941Smrgstatic void 619b8e80941Smrghandle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource) 620b8e80941Smrg{ 621b8e80941Smrg struct NineDevice9 *device = This->base.device; 622b8e80941Smrg struct pipe_blit_info blit; 623b8e80941Smrg struct pipe_context *pipe; 624b8e80941Smrg 625b8e80941Smrg if (device->cursor.software && device->cursor.visible && device->cursor.w) { 626b8e80941Smrg memset(&blit, 0, sizeof(blit)); 627b8e80941Smrg blit.src.resource = device->cursor.image; 628b8e80941Smrg blit.src.level = 0; 629b8e80941Smrg blit.src.format = device->cursor.image->format; 630b8e80941Smrg blit.src.box.x = 0; 631b8e80941Smrg blit.src.box.y = 0; 632b8e80941Smrg blit.src.box.z = 0; 633b8e80941Smrg blit.src.box.depth = 1; 634b8e80941Smrg blit.src.box.width = device->cursor.w; 635b8e80941Smrg blit.src.box.height = device->cursor.h; 636b8e80941Smrg 637b8e80941Smrg blit.dst.resource = resource; 638b8e80941Smrg blit.dst.level = 0; 639b8e80941Smrg blit.dst.format = resource->format; 640b8e80941Smrg blit.dst.box.z = 0; 641b8e80941Smrg blit.dst.box.depth = 1; 642b8e80941Smrg 643b8e80941Smrg blit.mask = PIPE_MASK_RGBA; 644b8e80941Smrg blit.filter = PIPE_TEX_FILTER_NEAREST; 645b8e80941Smrg blit.scissor_enable = FALSE; 646b8e80941Smrg 647b8e80941Smrg /* NOTE: blit messes up when box.x + box.width < 0, fix driver 648b8e80941Smrg * NOTE2: device->cursor.pos contains coordinates relative to the screen. 649b8e80941Smrg * This happens to be also the position of the cursor when we are fullscreen. 650b8e80941Smrg * We don't use sw cursor for Windowed mode */ 651b8e80941Smrg blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; 652b8e80941Smrg blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; 653b8e80941Smrg blit.dst.box.width = blit.src.box.width; 654b8e80941Smrg blit.dst.box.height = blit.src.box.height; 655b8e80941Smrg 656b8e80941Smrg DBG("Blitting cursor(%ux%u) to (%i,%i).\n", 657b8e80941Smrg blit.src.box.width, blit.src.box.height, 658b8e80941Smrg blit.dst.box.x, blit.dst.box.y); 659b8e80941Smrg 660b8e80941Smrg blit.alpha_blend = TRUE; 661b8e80941Smrg pipe = NineDevice9_GetPipe(This->base.device); 662b8e80941Smrg pipe->blit(pipe, &blit); 663b8e80941Smrg } 664b8e80941Smrg 665b8e80941Smrg if (device->hud && resource) { 666b8e80941Smrg /* Implicit use of context pipe */ 667b8e80941Smrg (void)NineDevice9_GetPipe(This->base.device); 668b8e80941Smrg hud_run(device->hud, NULL, resource); /* XXX: no offset */ 669b8e80941Smrg /* HUD doesn't clobber stipple */ 670b8e80941Smrg nine_state_restore_non_cso(device); 671b8e80941Smrg } 672b8e80941Smrg} 673b8e80941Smrg 674b8e80941Smrgstruct end_present_struct { 675b8e80941Smrg struct pipe_screen *screen; 676b8e80941Smrg struct pipe_fence_handle *fence_to_wait; 677b8e80941Smrg ID3DPresent *present; 678b8e80941Smrg D3DWindowBuffer *present_handle; 679b8e80941Smrg BOOL *pending_presentation; 680b8e80941Smrg HWND hDestWindowOverride; 681b8e80941Smrg}; 682b8e80941Smrg 683b8e80941Smrgstatic void work_present(void *data) 684b8e80941Smrg{ 685b8e80941Smrg struct end_present_struct *work = data; 686b8e80941Smrg if (work->fence_to_wait) { 687b8e80941Smrg (void) work->screen->fence_finish(work->screen, NULL, work->fence_to_wait, PIPE_TIMEOUT_INFINITE); 688b8e80941Smrg work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL); 689b8e80941Smrg } 690b8e80941Smrg ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0); 691b8e80941Smrg p_atomic_set(work->pending_presentation, FALSE); 692b8e80941Smrg free(work); 693b8e80941Smrg} 694b8e80941Smrg 695b8e80941Smrgstatic void pend_present(struct NineSwapChain9 *This, 696b8e80941Smrg struct pipe_fence_handle *fence, 697b8e80941Smrg HWND hDestWindowOverride) 698b8e80941Smrg{ 699b8e80941Smrg struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct)); 700b8e80941Smrg 701b8e80941Smrg work->screen = This->screen; 702b8e80941Smrg This->screen->fence_reference(This->screen, &work->fence_to_wait, fence); 703b8e80941Smrg work->present = This->present; 704b8e80941Smrg work->present_handle = This->present_handles[0]; 705b8e80941Smrg work->hDestWindowOverride = hDestWindowOverride; 706b8e80941Smrg work->pending_presentation = This->pending_presentation[0]; 707b8e80941Smrg p_atomic_set(work->pending_presentation, TRUE); 708b8e80941Smrg This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work); 709b8e80941Smrg 710b8e80941Smrg return; 711b8e80941Smrg} 712b8e80941Smrg 713b8e80941Smrgstatic inline HRESULT 714b8e80941Smrgpresent( struct NineSwapChain9 *This, 715b8e80941Smrg const RECT *pSourceRect, 716b8e80941Smrg const RECT *pDestRect, 717b8e80941Smrg HWND hDestWindowOverride, 718b8e80941Smrg const RGNDATA *pDirtyRegion, 719b8e80941Smrg DWORD dwFlags ) 720b8e80941Smrg{ 721b8e80941Smrg struct pipe_context *pipe; 722b8e80941Smrg struct pipe_resource *resource; 723b8e80941Smrg struct pipe_fence_handle *fence; 724b8e80941Smrg HRESULT hr; 725b8e80941Smrg struct pipe_blit_info blit; 726b8e80941Smrg int target_width, target_height, target_depth, i; 727b8e80941Smrg 728b8e80941Smrg DBG("present: This=%p pSourceRect=%p pDestRect=%p " 729b8e80941Smrg "pDirtyRegion=%p hDestWindowOverride=%p" 730b8e80941Smrg "dwFlags=%d resource=%p\n", 731b8e80941Smrg This, pSourceRect, pDestRect, pDirtyRegion, 732b8e80941Smrg hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource); 733b8e80941Smrg 734b8e80941Smrg if (pSourceRect) 735b8e80941Smrg DBG("pSourceRect = (%u..%u)x(%u..%u)\n", 736b8e80941Smrg pSourceRect->left, pSourceRect->right, 737b8e80941Smrg pSourceRect->top, pSourceRect->bottom); 738b8e80941Smrg if (pDestRect) 739b8e80941Smrg DBG("pDestRect = (%u..%u)x(%u..%u)\n", 740b8e80941Smrg pDestRect->left, pDestRect->right, 741b8e80941Smrg pDestRect->top, pDestRect->bottom); 742b8e80941Smrg 743b8e80941Smrg /* TODO: in the case the source and destination rect have different size: 744b8e80941Smrg * We need to allocate a new buffer, and do a blit to it to resize. 745b8e80941Smrg * We can't use the present_buffer for that since when we created it, 746b8e80941Smrg * we couldn't guess which size would have been needed. 747b8e80941Smrg * If pDestRect or pSourceRect is null, we have to check the sizes 748b8e80941Smrg * from the source size, and the destination window size. 749b8e80941Smrg * In this case, either resize rngdata, or pass NULL instead 750b8e80941Smrg */ 751b8e80941Smrg /* Note: This->buffers[0]->level should always be 0 */ 752b8e80941Smrg 753b8e80941Smrg if (This->rendering_done) 754b8e80941Smrg goto bypass_rendering; 755b8e80941Smrg 756b8e80941Smrg resource = This->buffers[0]->base.resource; 757b8e80941Smrg 758b8e80941Smrg if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD) 759b8e80941Smrg handle_draw_cursor_and_hud(This, resource); 760b8e80941Smrg 761b8e80941Smrg hr = ID3DPresent_GetWindowInfo(This->present, hDestWindowOverride, &target_width, &target_height, &target_depth); 762b8e80941Smrg (void)target_depth; 763b8e80941Smrg 764b8e80941Smrg /* Can happen with old Wine (presentation can still succeed), 765b8e80941Smrg * or at window destruction. 766b8e80941Smrg * Also disable for very old wine as D3DWindowBuffer_release 767b8e80941Smrg * cannot do the DestroyD3DWindowBuffer workaround. */ 768b8e80941Smrg if (FAILED(hr) || target_width == 0 || target_height == 0 || 769b8e80941Smrg This->base.device->minor_version_num <= 2) { 770b8e80941Smrg target_width = resource->width0; 771b8e80941Smrg target_height = resource->height0; 772b8e80941Smrg } 773b8e80941Smrg 774b8e80941Smrg /* Switch to using presentation buffers on window resize. 775b8e80941Smrg * Note: Most apps should resize the d3d back buffers when 776b8e80941Smrg * a window resize is detected, which will result in a call to 777b8e80941Smrg * NineSwapChain9_Resize. Thus everything will get released, 778b8e80941Smrg * and it will switch back to not using separate presentation 779b8e80941Smrg * buffers. */ 780b8e80941Smrg if (!This->present_buffers[0] && 781b8e80941Smrg (target_width != resource->width0 || target_height != resource->height0)) { 782b8e80941Smrg BOOL failure = false; 783b8e80941Smrg struct pipe_resource *new_resource[This->num_back_buffers]; 784b8e80941Smrg D3DWindowBuffer *new_handles[This->num_back_buffers]; 785b8e80941Smrg for (i = 0; i < This->num_back_buffers; i++) { 786b8e80941Smrg /* Note: if (!new_handles[i]), new_resource[i] 787b8e80941Smrg * gets released and contains NULL */ 788b8e80941Smrg create_present_buffer(This, target_width, target_height, &new_resource[i], &new_handles[i]); 789b8e80941Smrg if (!new_handles[i]) 790b8e80941Smrg failure = true; 791b8e80941Smrg } 792b8e80941Smrg if (failure) { 793b8e80941Smrg for (i = 0; i < This->num_back_buffers; i++) { 794b8e80941Smrg if (new_resource[i]) 795b8e80941Smrg pipe_resource_reference(&new_resource[i], NULL); 796b8e80941Smrg if (new_handles[i]) 797b8e80941Smrg D3DWindowBuffer_release(This, new_handles[i]); 798b8e80941Smrg } 799b8e80941Smrg } else { 800b8e80941Smrg for (i = 0; i < This->num_back_buffers; i++) { 801b8e80941Smrg D3DWindowBuffer_release(This, This->present_handles[i]); 802b8e80941Smrg This->present_handles[i] = new_handles[i]; 803b8e80941Smrg pipe_resource_reference(&This->present_buffers[i], new_resource[i]); 804b8e80941Smrg pipe_resource_reference(&new_resource[i], NULL); 805b8e80941Smrg } 806b8e80941Smrg } 807b8e80941Smrg } 808b8e80941Smrg 809b8e80941Smrg pipe = NineDevice9_GetPipe(This->base.device); 810b8e80941Smrg 811b8e80941Smrg if (This->present_buffers[0]) { 812b8e80941Smrg memset(&blit, 0, sizeof(blit)); 813b8e80941Smrg blit.src.resource = resource; 814b8e80941Smrg blit.src.level = 0; 815b8e80941Smrg blit.src.format = resource->format; 816b8e80941Smrg blit.src.box.z = 0; 817b8e80941Smrg blit.src.box.depth = 1; 818b8e80941Smrg blit.src.box.x = 0; 819b8e80941Smrg blit.src.box.y = 0; 820b8e80941Smrg blit.src.box.width = resource->width0; 821b8e80941Smrg blit.src.box.height = resource->height0; 822b8e80941Smrg 823b8e80941Smrg /* Reallocate a new presentation buffer if the target window 824b8e80941Smrg * size has changed */ 825b8e80941Smrg if (target_width != This->present_buffers[0]->width0 || 826b8e80941Smrg target_height != This->present_buffers[0]->height0) { 827b8e80941Smrg struct pipe_resource *new_resource; 828b8e80941Smrg D3DWindowBuffer *new_handle; 829b8e80941Smrg 830b8e80941Smrg create_present_buffer(This, target_width, target_height, &new_resource, &new_handle); 831b8e80941Smrg /* Switch to the new buffer */ 832b8e80941Smrg if (new_handle) { 833b8e80941Smrg D3DWindowBuffer_release(This, This->present_handles[0]); 834b8e80941Smrg This->present_handles[0] = new_handle; 835b8e80941Smrg pipe_resource_reference(&This->present_buffers[0], new_resource); 836b8e80941Smrg pipe_resource_reference(&new_resource, NULL); 837b8e80941Smrg } 838b8e80941Smrg } 839b8e80941Smrg 840b8e80941Smrg resource = This->present_buffers[0]; 841b8e80941Smrg 842b8e80941Smrg blit.dst.resource = resource; 843b8e80941Smrg blit.dst.level = 0; 844b8e80941Smrg blit.dst.format = resource->format; 845b8e80941Smrg blit.dst.box.z = 0; 846b8e80941Smrg blit.dst.box.depth = 1; 847b8e80941Smrg blit.dst.box.x = 0; 848b8e80941Smrg blit.dst.box.y = 0; 849b8e80941Smrg blit.dst.box.width = resource->width0; 850b8e80941Smrg blit.dst.box.height = resource->height0; 851b8e80941Smrg 852b8e80941Smrg blit.mask = PIPE_MASK_RGBA; 853b8e80941Smrg blit.filter = (blit.dst.box.width == blit.src.box.width && 854b8e80941Smrg blit.dst.box.height == blit.src.box.height) ? 855b8e80941Smrg PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR; 856b8e80941Smrg blit.scissor_enable = FALSE; 857b8e80941Smrg blit.alpha_blend = FALSE; 858b8e80941Smrg 859b8e80941Smrg pipe->blit(pipe, &blit); 860b8e80941Smrg } 861b8e80941Smrg 862b8e80941Smrg /* The resource we present has to resolve fast clears 863b8e80941Smrg * if needed (and other things) */ 864b8e80941Smrg pipe->flush_resource(pipe, resource); 865b8e80941Smrg 866b8e80941Smrg if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD) 867b8e80941Smrg handle_draw_cursor_and_hud(This, resource); 868b8e80941Smrg 869b8e80941Smrg fence = NULL; 870b8e80941Smrg pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME); 871b8e80941Smrg 872b8e80941Smrg /* Present now for thread_submit, because we have the fence. 873b8e80941Smrg * It's possible we return WASSTILLDRAWING and still Present, 874b8e80941Smrg * but it should be fine. */ 875b8e80941Smrg if (This->enable_threadpool) 876b8e80941Smrg pend_present(This, fence, hDestWindowOverride); 877b8e80941Smrg if (fence) { 878b8e80941Smrg swap_fences_push_back(This, fence); 879b8e80941Smrg This->screen->fence_reference(This->screen, &fence, NULL); 880b8e80941Smrg } 881b8e80941Smrg 882b8e80941Smrg This->rendering_done = TRUE; 883b8e80941Smrgbypass_rendering: 884b8e80941Smrg 885b8e80941Smrg if (dwFlags & D3DPRESENT_DONOTWAIT) { 886b8e80941Smrg UNTESTED(2); 887b8e80941Smrg BOOL still_draw = FALSE; 888b8e80941Smrg fence = swap_fences_see_front(This); 889b8e80941Smrg if (fence) { 890b8e80941Smrg still_draw = !This->screen->fence_finish(This->screen, NULL, fence, 0); 891b8e80941Smrg This->screen->fence_reference(This->screen, &fence, NULL); 892b8e80941Smrg } 893b8e80941Smrg if (still_draw) 894b8e80941Smrg return D3DERR_WASSTILLDRAWING; 895b8e80941Smrg } 896b8e80941Smrg 897b8e80941Smrg /* Throttle rendering if needed */ 898b8e80941Smrg fence = swap_fences_pop_front(This); 899b8e80941Smrg if (fence) { 900b8e80941Smrg (void) This->screen->fence_finish(This->screen, NULL, fence, PIPE_TIMEOUT_INFINITE); 901b8e80941Smrg This->screen->fence_reference(This->screen, &fence, NULL); 902b8e80941Smrg } 903b8e80941Smrg 904b8e80941Smrg This->rendering_done = FALSE; 905b8e80941Smrg 906b8e80941Smrg if (!This->enable_threadpool) { 907b8e80941Smrg This->tasks[0]=NULL; 908b8e80941Smrg 909b8e80941Smrg hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags); 910b8e80941Smrg 911b8e80941Smrg if (FAILED(hr)) { UNTESTED(3);return hr; } 912b8e80941Smrg } 913b8e80941Smrg 914b8e80941Smrg return D3D_OK; 915b8e80941Smrg} 916b8e80941Smrg 917b8e80941SmrgHRESULT NINE_WINAPI 918b8e80941SmrgNineSwapChain9_Present( struct NineSwapChain9 *This, 919b8e80941Smrg const RECT *pSourceRect, 920b8e80941Smrg const RECT *pDestRect, 921b8e80941Smrg HWND hDestWindowOverride, 922b8e80941Smrg const RGNDATA *pDirtyRegion, 923b8e80941Smrg DWORD dwFlags ) 924b8e80941Smrg{ 925b8e80941Smrg struct pipe_resource *res = NULL; 926b8e80941Smrg D3DWindowBuffer *handle_temp; 927b8e80941Smrg struct threadpool_task *task_temp; 928b8e80941Smrg BOOL *pending_presentation_temp; 929b8e80941Smrg int i; 930b8e80941Smrg HRESULT hr; 931b8e80941Smrg 932b8e80941Smrg DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " 933b8e80941Smrg "pDirtyRegion=%p dwFlags=%d\n", 934b8e80941Smrg This, pSourceRect, pDestRect, hDestWindowOverride, 935b8e80941Smrg pDirtyRegion,dwFlags); 936b8e80941Smrg 937b8e80941Smrg if (This->base.device->ex) { 938b8e80941Smrg if (NineSwapChain9_GetOccluded(This)) { 939b8e80941Smrg DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n"); 940b8e80941Smrg return S_PRESENT_OCCLUDED; 941b8e80941Smrg } 942b8e80941Smrg } else { 943b8e80941Smrg if (NineSwapChain9_GetOccluded(This) || 944b8e80941Smrg NineSwapChain9_ResolutionMismatch(This)) { 945b8e80941Smrg This->base.device->device_needs_reset = TRUE; 946b8e80941Smrg } 947b8e80941Smrg if (This->base.device->device_needs_reset) { 948b8e80941Smrg DBG("Device is lost. Returning D3DERR_DEVICELOST.\n"); 949b8e80941Smrg return D3DERR_DEVICELOST; 950b8e80941Smrg } 951b8e80941Smrg } 952b8e80941Smrg 953b8e80941Smrg nine_csmt_process(This->base.device); 954b8e80941Smrg 955b8e80941Smrg hr = present(This, pSourceRect, pDestRect, 956b8e80941Smrg hDestWindowOverride, pDirtyRegion, dwFlags); 957b8e80941Smrg if (hr == D3DERR_WASSTILLDRAWING) 958b8e80941Smrg return hr; 959b8e80941Smrg 960b8e80941Smrg if (This->base.device->minor_version_num > 2 && 961b8e80941Smrg This->actx->discard_delayed_release && 962b8e80941Smrg This->params.SwapEffect == D3DSWAPEFFECT_DISCARD && 963b8e80941Smrg This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { 964b8e80941Smrg int next_buffer = -1; 965b8e80941Smrg 966b8e80941Smrg while (next_buffer == -1) { 967b8e80941Smrg /* Find a free backbuffer */ 968b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) { 969b8e80941Smrg if (!p_atomic_read(This->pending_presentation[i]) && 970b8e80941Smrg ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) { 971b8e80941Smrg DBG("Found buffer released: %d\n", i); 972b8e80941Smrg next_buffer = i; 973b8e80941Smrg break; 974b8e80941Smrg } 975b8e80941Smrg } 976b8e80941Smrg if (next_buffer == -1) { 977b8e80941Smrg DBG("Found no buffer released. Waiting for event\n"); 978b8e80941Smrg ID3DPresent_WaitBufferReleaseEvent(This->present); 979b8e80941Smrg } 980b8e80941Smrg } 981b8e80941Smrg 982b8e80941Smrg /* Free the task (we already checked it is finished) */ 983b8e80941Smrg if (This->tasks[next_buffer]) 984b8e80941Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[next_buffer])); 985b8e80941Smrg assert(!*This->pending_presentation[next_buffer] && !This->tasks[next_buffer]); 986b8e80941Smrg This->tasks[next_buffer] = This->tasks[0]; 987b8e80941Smrg This->tasks[0] = NULL; 988b8e80941Smrg pending_presentation_temp = This->pending_presentation[next_buffer]; 989b8e80941Smrg This->pending_presentation[next_buffer] = This->pending_presentation[0]; 990b8e80941Smrg This->pending_presentation[0] = pending_presentation_temp; 991b8e80941Smrg 992b8e80941Smrg /* Switch with the released buffer */ 993b8e80941Smrg pipe_resource_reference(&res, This->buffers[0]->base.resource); 994b8e80941Smrg NineSurface9_SetResourceResize( 995b8e80941Smrg This->buffers[0], This->buffers[next_buffer]->base.resource); 996b8e80941Smrg NineSurface9_SetResourceResize( 997b8e80941Smrg This->buffers[next_buffer], res); 998b8e80941Smrg pipe_resource_reference(&res, NULL); 999b8e80941Smrg 1000b8e80941Smrg if (This->present_buffers[0]) { 1001b8e80941Smrg pipe_resource_reference(&res, This->present_buffers[0]); 1002b8e80941Smrg pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]); 1003b8e80941Smrg pipe_resource_reference(&This->present_buffers[next_buffer], res); 1004b8e80941Smrg pipe_resource_reference(&res, NULL); 1005b8e80941Smrg } 1006b8e80941Smrg 1007b8e80941Smrg handle_temp = This->present_handles[0]; 1008b8e80941Smrg This->present_handles[0] = This->present_handles[next_buffer]; 1009b8e80941Smrg This->present_handles[next_buffer] = handle_temp; 1010b8e80941Smrg } else { 1011b8e80941Smrg switch (This->params.SwapEffect) { 1012b8e80941Smrg case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */ 1013b8e80941Smrg case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */ 1014b8e80941Smrg case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */ 1015b8e80941Smrg case D3DSWAPEFFECT_FLIP: 1016b8e80941Smrg /* rotate the queue */ 1017b8e80941Smrg pipe_resource_reference(&res, This->buffers[0]->base.resource); 1018b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) { 1019b8e80941Smrg NineSurface9_SetResourceResize(This->buffers[i - 1], 1020b8e80941Smrg This->buffers[i]->base.resource); 1021b8e80941Smrg } 1022b8e80941Smrg NineSurface9_SetResourceResize( 1023b8e80941Smrg This->buffers[This->num_back_buffers - 1], res); 1024b8e80941Smrg pipe_resource_reference(&res, NULL); 1025b8e80941Smrg 1026b8e80941Smrg if (This->present_buffers[0]) { 1027b8e80941Smrg pipe_resource_reference(&res, This->present_buffers[0]); 1028b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) 1029b8e80941Smrg pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); 1030b8e80941Smrg pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); 1031b8e80941Smrg pipe_resource_reference(&res, NULL); 1032b8e80941Smrg } 1033b8e80941Smrg 1034b8e80941Smrg handle_temp = This->present_handles[0]; 1035b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) { 1036b8e80941Smrg This->present_handles[i-1] = This->present_handles[i]; 1037b8e80941Smrg } 1038b8e80941Smrg This->present_handles[This->num_back_buffers - 1] = handle_temp; 1039b8e80941Smrg task_temp = This->tasks[0]; 1040b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) { 1041b8e80941Smrg This->tasks[i-1] = This->tasks[i]; 1042b8e80941Smrg } 1043b8e80941Smrg This->tasks[This->num_back_buffers - 1] = task_temp; 1044b8e80941Smrg pending_presentation_temp = This->pending_presentation[0]; 1045b8e80941Smrg for (i = 1; i < This->num_back_buffers; i++) { 1046b8e80941Smrg This->pending_presentation[i-1] = This->pending_presentation[i]; 1047b8e80941Smrg } 1048b8e80941Smrg This->pending_presentation[This->num_back_buffers - 1] = pending_presentation_temp; 1049b8e80941Smrg break; 1050b8e80941Smrg 1051b8e80941Smrg case D3DSWAPEFFECT_COPY: 1052b8e80941Smrg /* do nothing */ 1053b8e80941Smrg break; 1054b8e80941Smrg } 1055b8e80941Smrg 1056b8e80941Smrg if (This->tasks[0]) 1057b8e80941Smrg _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); 1058b8e80941Smrg assert(!*This->pending_presentation[0]); 1059b8e80941Smrg 1060b8e80941Smrg ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); 1061b8e80941Smrg } 1062b8e80941Smrg 1063b8e80941Smrg This->base.device->context.changed.group |= NINE_STATE_FB; 1064b8e80941Smrg 1065b8e80941Smrg return hr; 1066b8e80941Smrg} 1067b8e80941Smrg 1068b8e80941SmrgHRESULT NINE_WINAPI 1069b8e80941SmrgNineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, 1070b8e80941Smrg IDirect3DSurface9 *pDestSurface ) 1071b8e80941Smrg{ 1072b8e80941Smrg struct NineSurface9 *dest_surface = NineSurface9(pDestSurface); 1073b8e80941Smrg struct NineDevice9 *pDevice = This->base.device; 1074b8e80941Smrg unsigned int width, height; 1075b8e80941Smrg struct pipe_resource *temp_resource; 1076b8e80941Smrg struct NineSurface9 *temp_surface; 1077b8e80941Smrg D3DWindowBuffer *temp_handle; 1078b8e80941Smrg D3DSURFACE_DESC desc; 1079b8e80941Smrg HRESULT hr; 1080b8e80941Smrg 1081b8e80941Smrg DBG("GetFrontBufferData: This=%p pDestSurface=%p\n", 1082b8e80941Smrg This, pDestSurface); 1083b8e80941Smrg 1084b8e80941Smrg user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL); 1085b8e80941Smrg 1086b8e80941Smrg width = dest_surface->desc.Width; 1087b8e80941Smrg height = dest_surface->desc.Height; 1088b8e80941Smrg 1089b8e80941Smrg /* Note: front window size and destination size are supposed 1090b8e80941Smrg * to match. However it's not very clear what should get taken in Windowed 1091b8e80941Smrg * mode. It may need a fix */ 1092b8e80941Smrg create_present_buffer(This, width, height, &temp_resource, &temp_handle); 1093b8e80941Smrg 1094b8e80941Smrg if (!temp_resource || !temp_handle) { 1095b8e80941Smrg return D3DERR_INVALIDCALL; 1096b8e80941Smrg } 1097b8e80941Smrg 1098b8e80941Smrg desc.Type = D3DRTYPE_SURFACE; 1099b8e80941Smrg desc.Pool = D3DPOOL_DEFAULT; 1100b8e80941Smrg desc.MultiSampleType = D3DMULTISAMPLE_NONE; 1101b8e80941Smrg desc.MultiSampleQuality = 0; 1102b8e80941Smrg desc.Width = width; 1103b8e80941Smrg desc.Height = height; 1104b8e80941Smrg /* NineSurface9_CopyDefaultToMem needs same format. */ 1105b8e80941Smrg desc.Format = dest_surface->desc.Format; 1106b8e80941Smrg desc.Usage = D3DUSAGE_RENDERTARGET; 1107b8e80941Smrg hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0, 1108b8e80941Smrg 0, 0, &desc, &temp_surface); 1109b8e80941Smrg pipe_resource_reference(&temp_resource, NULL); 1110b8e80941Smrg if (FAILED(hr)) { 1111b8e80941Smrg DBG("Failed to create temp FrontBuffer surface.\n"); 1112b8e80941Smrg return hr; 1113b8e80941Smrg } 1114b8e80941Smrg 1115b8e80941Smrg ID3DPresent_FrontBufferCopy(This->present, temp_handle); 1116b8e80941Smrg 1117b8e80941Smrg NineSurface9_CopyDefaultToMem(dest_surface, temp_surface); 1118b8e80941Smrg 1119b8e80941Smrg ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); 1120b8e80941Smrg NineUnknown_Destroy(NineUnknown(temp_surface)); 1121b8e80941Smrg 1122b8e80941Smrg return D3D_OK; 1123b8e80941Smrg} 1124b8e80941Smrg 1125b8e80941SmrgHRESULT NINE_WINAPI 1126b8e80941SmrgNineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, 1127b8e80941Smrg UINT iBackBuffer, 1128b8e80941Smrg D3DBACKBUFFER_TYPE Type, 1129b8e80941Smrg IDirect3DSurface9 **ppBackBuffer ) 1130b8e80941Smrg{ 1131b8e80941Smrg DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n", 1132b8e80941Smrg This, iBackBuffer, Type, ppBackBuffer); 1133b8e80941Smrg (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO); 1134b8e80941Smrg /* don't touch ppBackBuffer on error */ 1135b8e80941Smrg user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL); 1136b8e80941Smrg user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL); 1137b8e80941Smrg 1138b8e80941Smrg NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer])); 1139b8e80941Smrg *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer]; 1140b8e80941Smrg return D3D_OK; 1141b8e80941Smrg} 1142b8e80941Smrg 1143b8e80941SmrgHRESULT NINE_WINAPI 1144b8e80941SmrgNineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, 1145b8e80941Smrg D3DRASTER_STATUS *pRasterStatus ) 1146b8e80941Smrg{ 1147b8e80941Smrg DBG("GetRasterStatus: This=%p pRasterStatus=%p\n", 1148b8e80941Smrg This, pRasterStatus); 1149b8e80941Smrg user_assert(pRasterStatus != NULL, E_POINTER); 1150b8e80941Smrg return ID3DPresent_GetRasterStatus(This->present, pRasterStatus); 1151b8e80941Smrg} 1152b8e80941Smrg 1153b8e80941SmrgHRESULT NINE_WINAPI 1154b8e80941SmrgNineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, 1155b8e80941Smrg D3DDISPLAYMODE *pMode ) 1156b8e80941Smrg{ 1157b8e80941Smrg D3DDISPLAYMODEEX mode; 1158b8e80941Smrg D3DDISPLAYROTATION rot; 1159b8e80941Smrg HRESULT hr; 1160b8e80941Smrg 1161b8e80941Smrg DBG("GetDisplayMode: This=%p pMode=%p\n", 1162b8e80941Smrg This, pMode); 1163b8e80941Smrg user_assert(pMode != NULL, E_POINTER); 1164b8e80941Smrg 1165b8e80941Smrg hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot); 1166b8e80941Smrg if (SUCCEEDED(hr)) { 1167b8e80941Smrg pMode->Width = mode.Width; 1168b8e80941Smrg pMode->Height = mode.Height; 1169b8e80941Smrg pMode->RefreshRate = mode.RefreshRate; 1170b8e80941Smrg pMode->Format = mode.Format; 1171b8e80941Smrg } 1172b8e80941Smrg return hr; 1173b8e80941Smrg} 1174b8e80941Smrg 1175b8e80941SmrgHRESULT NINE_WINAPI 1176b8e80941SmrgNineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, 1177b8e80941Smrg D3DPRESENT_PARAMETERS *pPresentationParameters ) 1178b8e80941Smrg{ 1179b8e80941Smrg DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n", 1180b8e80941Smrg This, pPresentationParameters); 1181b8e80941Smrg user_assert(pPresentationParameters != NULL, E_POINTER); 1182b8e80941Smrg *pPresentationParameters = This->params; 1183b8e80941Smrg return D3D_OK; 1184b8e80941Smrg} 1185b8e80941Smrg 1186b8e80941SmrgIDirect3DSwapChain9Vtbl NineSwapChain9_vtable = { 1187b8e80941Smrg (void *)NineUnknown_QueryInterface, 1188b8e80941Smrg (void *)NineUnknown_AddRef, 1189b8e80941Smrg (void *)NineUnknown_Release, 1190b8e80941Smrg (void *)NineSwapChain9_Present, 1191b8e80941Smrg (void *)NineSwapChain9_GetFrontBufferData, 1192b8e80941Smrg (void *)NineSwapChain9_GetBackBuffer, 1193b8e80941Smrg (void *)NineSwapChain9_GetRasterStatus, 1194b8e80941Smrg (void *)NineSwapChain9_GetDisplayMode, 1195b8e80941Smrg (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */ 1196b8e80941Smrg (void *)NineSwapChain9_GetPresentParameters 1197b8e80941Smrg}; 1198b8e80941Smrg 1199b8e80941Smrgstatic const GUID *NineSwapChain9_IIDs[] = { 1200b8e80941Smrg &IID_IDirect3DSwapChain9, 1201b8e80941Smrg &IID_IUnknown, 1202b8e80941Smrg NULL 1203b8e80941Smrg}; 1204b8e80941Smrg 1205b8e80941SmrgHRESULT 1206b8e80941SmrgNineSwapChain9_new( struct NineDevice9 *pDevice, 1207b8e80941Smrg BOOL implicit, 1208b8e80941Smrg ID3DPresent *pPresent, 1209b8e80941Smrg D3DPRESENT_PARAMETERS *pPresentationParameters, 1210b8e80941Smrg struct d3dadapter9_context *pCTX, 1211b8e80941Smrg HWND hFocusWindow, 1212b8e80941Smrg struct NineSwapChain9 **ppOut ) 1213b8e80941Smrg{ 1214b8e80941Smrg NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */ 1215b8e80941Smrg implicit, pPresent, pPresentationParameters, 1216b8e80941Smrg pCTX, hFocusWindow, NULL); 1217b8e80941Smrg} 1218b8e80941Smrg 1219b8e80941SmrgBOOL 1220b8e80941SmrgNineSwapChain9_GetOccluded( struct NineSwapChain9 *This ) 1221b8e80941Smrg{ 1222b8e80941Smrg if (This->base.device->minor_version_num > 0) { 1223b8e80941Smrg return ID3DPresent_GetWindowOccluded(This->present); 1224b8e80941Smrg } 1225b8e80941Smrg 1226b8e80941Smrg return FALSE; 1227b8e80941Smrg} 1228b8e80941Smrg 1229b8e80941SmrgBOOL 1230b8e80941SmrgNineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This ) 1231b8e80941Smrg{ 1232b8e80941Smrg if (This->base.device->minor_version_num > 1) { 1233b8e80941Smrg return ID3DPresent_ResolutionMismatch(This->present); 1234b8e80941Smrg } 1235b8e80941Smrg 1236b8e80941Smrg return FALSE; 1237b8e80941Smrg} 1238b8e80941Smrg 1239b8e80941SmrgHANDLE 1240b8e80941SmrgNineSwapChain9_CreateThread( struct NineSwapChain9 *This, 1241b8e80941Smrg void *pFuncAddress, 1242b8e80941Smrg void *pParam ) 1243b8e80941Smrg{ 1244b8e80941Smrg if (This->base.device->minor_version_num > 1) { 1245b8e80941Smrg return ID3DPresent_CreateThread(This->present, pFuncAddress, pParam); 1246b8e80941Smrg } 1247b8e80941Smrg 1248b8e80941Smrg return NULL; 1249b8e80941Smrg} 1250b8e80941Smrg 1251b8e80941Smrgvoid 1252b8e80941SmrgNineSwapChain9_WaitForThread( struct NineSwapChain9 *This, 1253b8e80941Smrg HANDLE thread ) 1254b8e80941Smrg{ 1255b8e80941Smrg if (This->base.device->minor_version_num > 1) { 1256b8e80941Smrg (void) ID3DPresent_WaitForThread(This->present, thread); 1257b8e80941Smrg } 1258b8e80941Smrg} 1259b8e80941Smrg 1260b8e80941Smrgstatic int 1261b8e80941SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This, 1262b8e80941Smrg D3DPRESENT_PARAMETERS *pParams ) 1263b8e80941Smrg{ 1264b8e80941Smrg int count = pParams->BackBufferCount; 1265b8e80941Smrg 1266b8e80941Smrg /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip. 1267b8e80941Smrg * Here we don't get back the initial content of the screen. To emulate the behaviour 1268b8e80941Smrg * we allocate an additional buffer */ 1269b8e80941Smrg if (pParams->SwapEffect != D3DSWAPEFFECT_COPY) 1270b8e80941Smrg count++; 1271b8e80941Smrg /* With DISCARD, as there is no guarantee about the buffer contents, we can use 1272b8e80941Smrg * an arbitrary number of buffers */ 1273b8e80941Smrg if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) { 1274b8e80941Smrg /* thread_submit's can have maximum count or This->actx->throttling_value + 1 1275b8e80941Smrg * frames in flight being rendered and not shown. 1276b8e80941Smrg * Do not let count decrease that number */ 1277b8e80941Smrg if (This->actx->thread_submit && count < This->desired_fences) 1278b8e80941Smrg count = This->desired_fences; 1279b8e80941Smrg /* When we enable AllowDISCARDDelayedRelease, we must ensure 1280b8e80941Smrg * to have at least 4 buffers to meet INTERVAL_IMMEDIATE, 1281b8e80941Smrg * since the display server/compositor can hold 3 buffers 1282b8e80941Smrg * without releasing them: 1283b8e80941Smrg * . Buffer on screen. 1284b8e80941Smrg * . Buffer scheduled kernel side to be next on screen. 1285b8e80941Smrg * . Last buffer sent. */ 1286b8e80941Smrg if (This->base.device->minor_version_num > 2 && 1287b8e80941Smrg This->actx->discard_delayed_release && 1288b8e80941Smrg pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) { 1289b8e80941Smrg if (This->actx->thread_submit && count < 4) 1290b8e80941Smrg count = 4; 1291b8e80941Smrg /* When thread_submit is not used, 5 buffers are actually needed, 1292b8e80941Smrg * because in case a pageflip is missed because rendering wasn't finished, 1293b8e80941Smrg * the Xserver will hold 4 buffers. */ 1294b8e80941Smrg else if (!This->actx->thread_submit && count < 5) 1295b8e80941Smrg count = 5; 1296b8e80941Smrg } 1297b8e80941Smrg } 1298b8e80941Smrg 1299b8e80941Smrg return count; 1300b8e80941Smrg} 1301