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