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