2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
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:
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
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. */
23 #include "swapchain9.h"
27 #include "nine_helpers.h"
28 #include "nine_pipe.h"
29 #include "nine_dump.h"
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 "frontend/drm_driver.h"
37 #include "threadpool.h"
39 #define DBG_CHANNEL DBG_SWAPCHAIN
41 #define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
44 NineSwapChain9_ctor( struct NineSwapChain9
*This
,
45 struct NineUnknownParams
*pParams
,
47 ID3DPresent
*pPresent
,
48 D3DPRESENT_PARAMETERS
*pPresentationParameters
,
49 struct d3dadapter9_context
*pCTX
,
51 D3DDISPLAYMODEEX
*mode
)
56 DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
57 This
, pParams
->device
, pPresent
, pCTX
, hFocusWindow
);
59 hr
= NineUnknown_ctor(&This
->base
, pParams
);
63 This
->screen
= NineDevice9_GetScreen(This
->base
.device
);
64 This
->implicit
= implicit
;
66 This
->present
= pPresent
;
69 ID3DPresent_AddRef(pPresent
);
70 if (This
->base
.device
->minor_version_num
> 2) {
71 D3DPRESENT_PARAMETERS2 params2
;
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
);
79 if (!pPresentationParameters
->hDeviceWindow
)
80 pPresentationParameters
->hDeviceWindow
= hFocusWindow
;
82 This
->rendering_done
= FALSE
;
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
])
89 return NineSwapChain9_Resize(This
, pPresentationParameters
, mode
);
92 static D3DWindowBuffer
*
93 D3DWindowBuffer_create(struct NineSwapChain9
*This
,
94 struct pipe_resource
*resource
,
96 int for_frontbuffer_reading
)
99 struct pipe_context
*pipe
= nine_context_get_pipe_acquire(This
->base
.device
);
100 struct winsys_handle whandle
;
101 int stride
, dmaBufFd
;
104 memset(&whandle
, 0, sizeof(whandle
));
105 whandle
.type
= WINSYS_HANDLE_TYPE_FD
;
106 This
->screen
->resource_get_handle(This
->screen
, pipe
, resource
,
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
,
122 assert (SUCCEEDED(hr
));
125 ERR("Failed to create new D3DWindowBufferFromDmaBuf\n");
132 D3DWindowBuffer_release(struct NineSwapChain9
*This
,
133 D3DWindowBuffer
*present_handle
)
137 /* IsBufferReleased API not available */
138 if (This
->base
.device
->minor_version_num
<= 2) {
139 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, present_handle
);
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
;
150 if (i
== (D3DPRESENT_BACK_BUFFERS_MAX_EX
+ 1)) {
151 ERR("Server not releasing buffers...\n");
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
;
173 NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9
*This
,
174 D3DPRESENT_PARAMETERS
*pParams
);
177 NineSwapChain9_Resize( struct NineSwapChain9
*This
,
178 D3DPRESENT_PARAMETERS
*pParams
,
179 D3DDISPLAYMODEEX
*mode
)
181 struct NineDevice9
*pDevice
= This
->base
.device
;
182 D3DSURFACE_DESC desc
;
184 struct pipe_resource
*resource
, tmplt
;
186 BOOL has_present_buffers
= FALSE
;
188 unsigned i
, oldBufferCount
, newBufferCount
;
189 D3DMULTISAMPLE_TYPE multisample_type
;
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
);
206 "BackBufferWidth: %u\n"
207 "BackBufferHeight: %u\n"
208 "BackBufferFormat: %s\n"
209 "BackBufferCount: %u\n"
210 "MultiSampleType: %u\n"
211 "MultiSampleQuality: %u\n"
213 "hDeviceWindow: %p\n"
215 "EnableAutoDepthStencil: %i\n"
216 "AutoDepthStencilFormat: %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
);
231 if (pParams
->BackBufferCount
== 0) {
232 pParams
->BackBufferCount
= 1;
235 if (pParams
->BackBufferFormat
== D3DFMT_UNKNOWN
) {
236 pParams
->BackBufferFormat
= D3DFMT_A8R8G8B8
;
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
;
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
;
249 if (mode
&& This
->mode
) {
250 *(This
->mode
) = *mode
;
252 This
->mode
= malloc(sizeof(D3DDISPLAYMODEEX
));
253 memcpy(This
->mode
, mode
, sizeof(D3DDISPLAYMODEEX
));
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
);
265 oldBufferCount
= This
->num_back_buffers
;
266 newBufferCount
= NineSwapChain9_GetBackBufferCountForParams(This
, pParams
);
268 multisample_type
= pParams
->MultiSampleType
;
270 /* Map MultiSampleQuality to MultiSampleType */
271 hr
= d3dmultisample_type_check(This
->screen
, pParams
->BackBufferFormat
,
273 pParams
->MultiSampleQuality
,
279 pf
= d3d9_to_pipe_format_checked(This
->screen
, pParams
->BackBufferFormat
,
280 PIPE_TEXTURE_2D
, multisample_type
,
281 PIPE_BIND_RENDER_TARGET
, FALSE
, FALSE
);
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
;
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.*/
301 memset(&tmplt
, 0, sizeof(tmplt
));
302 tmplt
.target
= PIPE_TEXTURE_2D
;
303 tmplt
.width0
= pParams
->BackBufferWidth
;
304 tmplt
.height0
= pParams
->BackBufferHeight
;
306 tmplt
.last_level
= 0;
307 tmplt
.array_size
= 1;
308 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
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
;
318 for (i
= 0; i
< oldBufferCount
; i
++) {
320 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[i
]));
322 memset(This
->tasks
, 0, sizeof(This
->tasks
));
325 _mesa_threadpool_destroy(This
, This
->pool
);
328 This
->enable_threadpool
= This
->actx
->thread_submit
&& (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
);
329 if (This
->enable_threadpool
)
330 This
->pool
= _mesa_threadpool_create(This
);
332 This
->enable_threadpool
= FALSE
;
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
);
341 if (newBufferCount
!= oldBufferCount
) {
342 for (i
= newBufferCount
; i
< oldBufferCount
;
344 NineUnknown_Detach(NineUnknown(This
->buffers
[i
]));
346 for (i
= oldBufferCount
; i
< newBufferCount
; ++i
) {
347 This
->buffers
[i
] = NULL
;
348 This
->present_handles
[i
] = NULL
;
351 This
->num_back_buffers
= newBufferCount
;
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
,
363 tmplt
.bind
, FALSE
, FALSE
);
364 if (tmplt
.format
== PIPE_FORMAT_NONE
)
365 return D3DERR_INVALIDCALL
;
366 resource
= nine_resource_create_with_retry(pDevice
, This
->screen
, &tmplt
);
368 DBG("Failed to create pipe_resource.\n");
369 return D3DERR_OUTOFVIDEOMEMORY
;
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
);
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
);
386 DBG("Failed to create RT surface.\n");
389 This
->buffers
[i
]->base
.base
.forward
= FALSE
;
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
= nine_resource_create_with_retry(pDevice
, This
->screen
, &tmplt
);
401 pipe_resource_reference(&(This
->present_buffers
[i
]), resource
);
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
;
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
,
420 if (tmplt
.format
== PIPE_FORMAT_NONE
)
421 return D3DERR_INVALIDCALL
;
424 resource
= nine_resource_create_with_retry(pDevice
, This
->screen
, &tmplt
);
426 DBG("Failed to create pipe_resource for depth buffer.\n");
427 return D3DERR_OUTOFVIDEOMEMORY
;
430 NineSurface9_SetMultiSampleType(This
->zsbuf
, desc
.MultiSampleType
);
431 NineSurface9_SetResourceResize(This
->zsbuf
, resource
);
432 pipe_resource_reference(&resource
, NULL
);
434 hr
= NineDevice9_CreateDepthStencilSurface(pDevice
,
435 pParams
->BackBufferWidth
,
436 pParams
->BackBufferHeight
,
437 pParams
->AutoDepthStencilFormat
,
438 pParams
->MultiSampleType
,
439 pParams
->MultiSampleQuality
,
441 (IDirect3DSurface9
**)&This
->zsbuf
,
444 DBG("Failed to create ZS surface.\n");
447 NineUnknown_ConvertRefToBind(NineUnknown(This
->zsbuf
));
451 This
->params
= *pParams
;
456 /* Throttling: code adapted from the dri frontend */
459 * swap_fences_pop_front - pull a fence from the throttle queue
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.
465 static struct pipe_fence_handle
*
466 swap_fences_pop_front(struct NineSwapChain9
*This
)
468 struct pipe_screen
*screen
= This
->screen
;
469 struct pipe_fence_handle
*fence
= NULL
;
471 if (This
->desired_fences
== 0)
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
;
485 * swap_fences_see_front - same than swap_fences_pop_front without
490 static struct pipe_fence_handle
*
491 swap_fences_see_front(struct NineSwapChain9
*This
)
493 struct pipe_screen
*screen
= This
->screen
;
494 struct pipe_fence_handle
*fence
= NULL
;
496 if (This
->desired_fences
== 0)
499 if (This
->cur_fences
>= This
->desired_fences
) {
500 screen
->fence_reference(screen
, &fence
, This
->swap_fences
[This
->tail
]);
507 * swap_fences_push_back - push a fence onto the throttle queue at the back
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.
513 swap_fences_push_back(struct NineSwapChain9
*This
,
514 struct pipe_fence_handle
*fence
)
516 struct pipe_screen
*screen
= This
->screen
;
518 if (!fence
|| This
->desired_fences
== 0)
521 while(This
->cur_fences
== This
->desired_fences
)
522 swap_fences_pop_front(This
);
525 screen
->fence_reference(screen
, &This
->swap_fences
[This
->head
++],
527 This
->head
&= DRI_SWAP_FENCES_MASK
;
532 * swap_fences_unref - empty the throttle queue
534 * pulls fences of the throttle queue until it is empty.
537 swap_fences_unref(struct NineSwapChain9
*This
)
539 struct pipe_screen
*screen
= This
->screen
;
541 while(This
->cur_fences
) {
542 screen
->fence_reference(screen
, &This
->swap_fences
[This
->tail
++], NULL
);
543 This
->tail
&= DRI_SWAP_FENCES_MASK
;
549 NineSwapChain9_dtor( struct NineSwapChain9
*This
)
553 DBG("This=%p\n", This
);
556 _mesa_threadpool_destroy(This
, This
->pool
);
558 for (i
= 0; i
< D3DPRESENT_BACK_BUFFERS_MAX_EX
+ 1; i
++) {
559 if (This
->pending_presentation
[i
])
560 FREE(This
->pending_presentation
[i
]);
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
]);
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
);
577 NineUnknown_Unbind(NineUnknown(This
->zsbuf
));
580 ID3DPresent_Release(This
->present
);
582 swap_fences_unref(This
);
583 NineUnknown_dtor(&This
->base
);
587 create_present_buffer( struct NineSwapChain9
*This
,
588 unsigned int width
, unsigned int height
,
589 struct pipe_resource
**resource
,
590 D3DWindowBuffer
**present_handle
)
592 struct pipe_resource tmplt
;
594 memset(&tmplt
, 0, sizeof(tmplt
));
595 tmplt
.target
= PIPE_TEXTURE_2D
;
596 tmplt
.width0
= width
;
597 tmplt
.height0
= height
;
599 tmplt
.last_level
= 0;
600 tmplt
.array_size
= 1;
601 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
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
= nine_resource_create_with_retry(This
->base
.device
, This
->screen
, &tmplt
);
611 *present_handle
= D3DWindowBuffer_create(This
, *resource
, 24, true);
613 if (!*present_handle
) {
614 pipe_resource_reference(resource
, NULL
);
619 handle_draw_cursor_and_hud( struct NineSwapChain9
*This
, struct pipe_resource
*resource
)
621 struct NineDevice9
*device
= This
->base
.device
;
622 struct pipe_blit_info blit
;
623 struct pipe_context
*pipe
;
625 if (device
->cursor
.software
&& device
->cursor
.visible
&& device
->cursor
.w
) {
626 memset(&blit
, 0, sizeof(blit
));
627 blit
.src
.resource
= device
->cursor
.image
;
629 blit
.src
.format
= device
->cursor
.image
->format
;
633 blit
.src
.box
.depth
= 1;
634 blit
.src
.box
.width
= device
->cursor
.w
;
635 blit
.src
.box
.height
= device
->cursor
.h
;
637 blit
.dst
.resource
= resource
;
639 blit
.dst
.format
= resource
->format
;
641 blit
.dst
.box
.depth
= 1;
643 blit
.mask
= PIPE_MASK_RGBA
;
644 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
645 blit
.scissor_enable
= FALSE
;
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
;
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
);
660 blit
.alpha_blend
= TRUE
;
661 pipe
= NineDevice9_GetPipe(This
->base
.device
);
662 pipe
->blit(pipe
, &blit
);
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
);
674 struct 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
;
683 static void work_present(void *data
)
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
);
690 ID3DPresent_PresentBuffer(work
->present
, work
->present_handle
, work
->hDestWindowOverride
, NULL
, NULL
, NULL
, 0);
691 p_atomic_set(work
->pending_presentation
, FALSE
);
695 static void pend_present(struct NineSwapChain9
*This
,
696 struct pipe_fence_handle
*fence
,
697 HWND hDestWindowOverride
)
699 struct end_present_struct
*work
= calloc(1, sizeof(struct end_present_struct
));
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
);
713 static inline HRESULT
714 present( struct NineSwapChain9
*This
,
715 const RECT
*pSourceRect
,
716 const RECT
*pDestRect
,
717 HWND hDestWindowOverride
,
718 const RGNDATA
*pDirtyRegion
,
721 struct pipe_context
*pipe
;
722 struct pipe_resource
*resource
;
723 struct pipe_fence_handle
*fence
;
725 struct pipe_blit_info blit
;
726 int target_width
, target_height
, target_depth
, i
;
730 DBG("present: This=%p pSourceRect=%p pDestRect=%p "
731 "pDirtyRegion=%p hDestWindowOverride=%p"
732 "dwFlags=%d resource=%p\n",
733 This
, pSourceRect
, pDestRect
, pDirtyRegion
,
734 hDestWindowOverride
, (int)dwFlags
, This
->buffers
[0]->base
.resource
);
736 /* We can choose to only update pDirtyRegion, but the backend can choose
737 * to update everything. Let's ignore */
741 DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
742 pSourceRect
->left
, pSourceRect
->right
,
743 pSourceRect
->top
, pSourceRect
->bottom
);
744 source_rect
= *pSourceRect
;
747 DBG("pDestRect = (%u..%u)x(%u..%u)\n",
748 pDestRect
->left
, pDestRect
->right
,
749 pDestRect
->top
, pDestRect
->bottom
);
750 dest_rect
= *pDestRect
;
753 /* TODO: in the case the source and destination rect have different size:
754 * We need to allocate a new buffer, and do a blit to it to resize.
755 * We can't use the present_buffer for that since when we created it,
756 * we couldn't guess which size would have been needed.
757 * If pDestRect or pSourceRect is null, we have to check the sizes
758 * from the source size, and the destination window size.
759 * In this case, either resize rngdata, or pass NULL instead
761 /* Note: This->buffers[0]->level should always be 0 */
763 if (This
->rendering_done
)
764 goto bypass_rendering
;
766 resource
= This
->buffers
[0]->base
.resource
;
768 if (This
->params
.SwapEffect
== D3DSWAPEFFECT_DISCARD
)
769 handle_draw_cursor_and_hud(This
, resource
);
771 hr
= ID3DPresent_GetWindowInfo(This
->present
, hDestWindowOverride
, &target_width
, &target_height
, &target_depth
);
774 /* Can happen with old Wine (presentation can still succeed),
775 * or at window destruction.
776 * Also disable for very old wine as D3DWindowBuffer_release
777 * cannot do the DestroyD3DWindowBuffer workaround. */
778 if (FAILED(hr
) || target_width
== 0 || target_height
== 0 ||
779 This
->base
.device
->minor_version_num
<= 2) {
780 target_width
= resource
->width0
;
781 target_height
= resource
->height0
;
785 dest_rect
.top
= MAX2(0, dest_rect
.top
);
786 dest_rect
.left
= MAX2(0, dest_rect
.left
);
787 dest_rect
.bottom
= MIN2(target_height
, dest_rect
.bottom
);
788 dest_rect
.right
= MIN2(target_width
, dest_rect
.right
);
789 target_height
= dest_rect
.bottom
- dest_rect
.top
;
790 target_width
= dest_rect
.right
- dest_rect
.left
;
793 /* Switch to using presentation buffers on window resize.
794 * Note: Most apps should resize the d3d back buffers when
795 * a window resize is detected, which will result in a call to
796 * NineSwapChain9_Resize. Thus everything will get released,
797 * and it will switch back to not using separate presentation
799 if (!This
->present_buffers
[0] &&
800 (target_width
!= resource
->width0
|| target_height
!= resource
->height0
)) {
801 BOOL failure
= false;
802 struct pipe_resource
*new_resource
[This
->num_back_buffers
];
803 D3DWindowBuffer
*new_handles
[This
->num_back_buffers
];
804 for (i
= 0; i
< This
->num_back_buffers
; i
++) {
805 /* Note: if (!new_handles[i]), new_resource[i]
806 * gets released and contains NULL */
807 create_present_buffer(This
, target_width
, target_height
, &new_resource
[i
], &new_handles
[i
]);
812 for (i
= 0; i
< This
->num_back_buffers
; i
++) {
814 pipe_resource_reference(&new_resource
[i
], NULL
);
816 D3DWindowBuffer_release(This
, new_handles
[i
]);
819 for (i
= 0; i
< This
->num_back_buffers
; i
++) {
820 D3DWindowBuffer_release(This
, This
->present_handles
[i
]);
821 This
->present_handles
[i
] = new_handles
[i
];
822 pipe_resource_reference(&This
->present_buffers
[i
], new_resource
[i
]);
823 pipe_resource_reference(&new_resource
[i
], NULL
);
828 pipe
= NineDevice9_GetPipe(This
->base
.device
);
830 if (This
->present_buffers
[0]) {
831 memset(&blit
, 0, sizeof(blit
));
832 blit
.src
.resource
= resource
;
834 blit
.src
.format
= resource
->format
;
836 blit
.src
.box
.depth
= 1;
839 blit
.src
.box
.width
= resource
->width0
;
840 blit
.src
.box
.height
= resource
->height0
;
842 /* Reallocate a new presentation buffer if the target window
843 * size has changed */
844 if (target_width
!= This
->present_buffers
[0]->width0
||
845 target_height
!= This
->present_buffers
[0]->height0
) {
846 struct pipe_resource
*new_resource
;
847 D3DWindowBuffer
*new_handle
;
849 create_present_buffer(This
, target_width
, target_height
, &new_resource
, &new_handle
);
850 /* Switch to the new buffer */
852 D3DWindowBuffer_release(This
, This
->present_handles
[0]);
853 This
->present_handles
[0] = new_handle
;
854 pipe_resource_reference(&This
->present_buffers
[0], new_resource
);
855 pipe_resource_reference(&new_resource
, NULL
);
859 resource
= This
->present_buffers
[0];
861 blit
.dst
.resource
= resource
;
863 blit
.dst
.format
= resource
->format
;
865 blit
.dst
.box
.depth
= 1;
868 blit
.dst
.box
.width
= resource
->width0
;
869 blit
.dst
.box
.height
= resource
->height0
;
871 blit
.mask
= PIPE_MASK_RGBA
;
872 blit
.filter
= (blit
.dst
.box
.width
== blit
.src
.box
.width
&&
873 blit
.dst
.box
.height
== blit
.src
.box
.height
) ?
874 PIPE_TEX_FILTER_NEAREST
: PIPE_TEX_FILTER_LINEAR
;
875 blit
.scissor_enable
= FALSE
;
876 blit
.alpha_blend
= FALSE
;
878 pipe
->blit(pipe
, &blit
);
881 /* The resource we present has to resolve fast clears
882 * if needed (and other things) */
883 pipe
->flush_resource(pipe
, resource
);
885 if (This
->params
.SwapEffect
!= D3DSWAPEFFECT_DISCARD
)
886 handle_draw_cursor_and_hud(This
, resource
);
889 pipe
->flush(pipe
, &fence
, PIPE_FLUSH_END_OF_FRAME
);
891 /* Present now for thread_submit, because we have the fence.
892 * It's possible we return WASSTILLDRAWING and still Present,
893 * but it should be fine. */
894 if (This
->enable_threadpool
)
895 pend_present(This
, fence
, hDestWindowOverride
);
897 swap_fences_push_back(This
, fence
);
898 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
901 This
->rendering_done
= TRUE
;
904 if (dwFlags
& D3DPRESENT_DONOTWAIT
) {
906 BOOL still_draw
= FALSE
;
907 fence
= swap_fences_see_front(This
);
909 still_draw
= !This
->screen
->fence_finish(This
->screen
, NULL
, fence
, 0);
910 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
913 return D3DERR_WASSTILLDRAWING
;
916 /* Throttle rendering if needed */
917 fence
= swap_fences_pop_front(This
);
919 (void) This
->screen
->fence_finish(This
->screen
, NULL
, fence
, PIPE_TIMEOUT_INFINITE
);
920 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
923 This
->rendering_done
= FALSE
;
925 if (!This
->enable_threadpool
) {
928 hr
= ID3DPresent_PresentBuffer(This
->present
, This
->present_handles
[0], hDestWindowOverride
, pSourceRect
, pDestRect
? &dest_rect
: NULL
, NULL
, dwFlags
);
930 if (FAILED(hr
)) { UNTESTED(3);return hr
; }
937 NineSwapChain9_Present( struct NineSwapChain9
*This
,
938 const RECT
*pSourceRect
,
939 const RECT
*pDestRect
,
940 HWND hDestWindowOverride
,
941 const RGNDATA
*pDirtyRegion
,
944 struct pipe_resource
*res
= NULL
;
945 D3DWindowBuffer
*handle_temp
;
946 struct threadpool_task
*task_temp
;
947 BOOL
*pending_presentation_temp
;
951 DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
952 "pDirtyRegion=%p dwFlags=%d\n",
953 This
, pSourceRect
, pDestRect
, hDestWindowOverride
,
954 pDirtyRegion
,dwFlags
);
956 if (This
->base
.device
->ex
) {
957 if (NineSwapChain9_GetOccluded(This
)) {
958 DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n");
959 return S_PRESENT_OCCLUDED
;
962 if (NineSwapChain9_GetOccluded(This
) ||
963 NineSwapChain9_ResolutionMismatch(This
)) {
964 This
->base
.device
->device_needs_reset
= TRUE
;
966 if (This
->base
.device
->device_needs_reset
) {
967 DBG("Device is lost. Returning D3DERR_DEVICELOST.\n");
968 return D3DERR_DEVICELOST
;
972 nine_csmt_process(This
->base
.device
);
974 hr
= present(This
, pSourceRect
, pDestRect
,
975 hDestWindowOverride
, pDirtyRegion
, dwFlags
);
976 if (hr
== D3DERR_WASSTILLDRAWING
)
979 if (This
->base
.device
->minor_version_num
> 2 &&
980 This
->actx
->discard_delayed_release
&&
981 This
->params
.SwapEffect
== D3DSWAPEFFECT_DISCARD
&&
982 This
->params
.PresentationInterval
== D3DPRESENT_INTERVAL_IMMEDIATE
) {
983 int next_buffer
= -1;
985 while (next_buffer
== -1) {
986 /* Find a free backbuffer */
987 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
988 if (!p_atomic_read(This
->pending_presentation
[i
]) &&
989 ID3DPresent_IsBufferReleased(This
->present
, This
->present_handles
[i
])) {
990 DBG("Found buffer released: %d\n", i
);
995 if (next_buffer
== -1) {
996 DBG("Found no buffer released. Waiting for event\n");
997 ID3DPresent_WaitBufferReleaseEvent(This
->present
);
1001 /* Free the task (we already checked it is finished) */
1002 if (This
->tasks
[next_buffer
])
1003 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[next_buffer
]));
1004 assert(!*This
->pending_presentation
[next_buffer
] && !This
->tasks
[next_buffer
]);
1005 This
->tasks
[next_buffer
] = This
->tasks
[0];
1006 This
->tasks
[0] = NULL
;
1007 pending_presentation_temp
= This
->pending_presentation
[next_buffer
];
1008 This
->pending_presentation
[next_buffer
] = This
->pending_presentation
[0];
1009 This
->pending_presentation
[0] = pending_presentation_temp
;
1011 /* Switch with the released buffer */
1012 pipe_resource_reference(&res
, This
->buffers
[0]->base
.resource
);
1013 NineSurface9_SetResourceResize(
1014 This
->buffers
[0], This
->buffers
[next_buffer
]->base
.resource
);
1015 NineSurface9_SetResourceResize(
1016 This
->buffers
[next_buffer
], res
);
1017 pipe_resource_reference(&res
, NULL
);
1019 if (This
->present_buffers
[0]) {
1020 pipe_resource_reference(&res
, This
->present_buffers
[0]);
1021 pipe_resource_reference(&This
->present_buffers
[0], This
->present_buffers
[next_buffer
]);
1022 pipe_resource_reference(&This
->present_buffers
[next_buffer
], res
);
1023 pipe_resource_reference(&res
, NULL
);
1026 handle_temp
= This
->present_handles
[0];
1027 This
->present_handles
[0] = This
->present_handles
[next_buffer
];
1028 This
->present_handles
[next_buffer
] = handle_temp
;
1030 switch (This
->params
.SwapEffect
) {
1031 case D3DSWAPEFFECT_OVERLAY
: /* Not implemented, fallback to FLIP */
1032 case D3DSWAPEFFECT_FLIPEX
: /* Allows optimizations over FLIP for windowed mode. */
1033 case D3DSWAPEFFECT_DISCARD
: /* Allows optimizations over FLIP */
1034 case D3DSWAPEFFECT_FLIP
:
1035 /* rotate the queue */
1036 pipe_resource_reference(&res
, This
->buffers
[0]->base
.resource
);
1037 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
1038 NineSurface9_SetResourceResize(This
->buffers
[i
- 1],
1039 This
->buffers
[i
]->base
.resource
);
1041 NineSurface9_SetResourceResize(
1042 This
->buffers
[This
->num_back_buffers
- 1], res
);
1043 pipe_resource_reference(&res
, NULL
);
1045 if (This
->present_buffers
[0]) {
1046 pipe_resource_reference(&res
, This
->present_buffers
[0]);
1047 for (i
= 1; i
< This
->num_back_buffers
; i
++)
1048 pipe_resource_reference(&(This
->present_buffers
[i
-1]), This
->present_buffers
[i
]);
1049 pipe_resource_reference(&(This
->present_buffers
[This
->num_back_buffers
- 1]), res
);
1050 pipe_resource_reference(&res
, NULL
);
1053 handle_temp
= This
->present_handles
[0];
1054 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
1055 This
->present_handles
[i
-1] = This
->present_handles
[i
];
1057 This
->present_handles
[This
->num_back_buffers
- 1] = handle_temp
;
1058 task_temp
= This
->tasks
[0];
1059 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
1060 This
->tasks
[i
-1] = This
->tasks
[i
];
1062 This
->tasks
[This
->num_back_buffers
- 1] = task_temp
;
1063 pending_presentation_temp
= This
->pending_presentation
[0];
1064 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
1065 This
->pending_presentation
[i
-1] = This
->pending_presentation
[i
];
1067 This
->pending_presentation
[This
->num_back_buffers
- 1] = pending_presentation_temp
;
1070 case D3DSWAPEFFECT_COPY
:
1076 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[0]));
1077 assert(!*This
->pending_presentation
[0]);
1079 ID3DPresent_WaitBufferReleased(This
->present
, This
->present_handles
[0]);
1082 This
->base
.device
->context
.changed
.group
|= NINE_STATE_FB
;
1088 NineSwapChain9_GetFrontBufferData( struct NineSwapChain9
*This
,
1089 IDirect3DSurface9
*pDestSurface
)
1091 struct NineSurface9
*dest_surface
= NineSurface9(pDestSurface
);
1092 struct NineDevice9
*pDevice
= This
->base
.device
;
1093 unsigned int width
, height
;
1094 struct pipe_resource
*temp_resource
;
1095 struct NineSurface9
*temp_surface
;
1096 D3DWindowBuffer
*temp_handle
;
1097 D3DSURFACE_DESC desc
;
1100 DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
1101 This
, pDestSurface
);
1103 user_assert(dest_surface
->base
.pool
== D3DPOOL_SYSTEMMEM
, D3DERR_INVALIDCALL
);
1105 width
= dest_surface
->desc
.Width
;
1106 height
= dest_surface
->desc
.Height
;
1108 /* Note: front window size and destination size are supposed
1109 * to match. However it's not very clear what should get taken in Windowed
1110 * mode. It may need a fix */
1111 create_present_buffer(This
, width
, height
, &temp_resource
, &temp_handle
);
1113 if (!temp_resource
|| !temp_handle
) {
1114 return D3DERR_INVALIDCALL
;
1117 desc
.Type
= D3DRTYPE_SURFACE
;
1118 desc
.Pool
= D3DPOOL_DEFAULT
;
1119 desc
.MultiSampleType
= D3DMULTISAMPLE_NONE
;
1120 desc
.MultiSampleQuality
= 0;
1122 desc
.Height
= height
;
1123 /* NineSurface9_CopyDefaultToMem needs same format. */
1124 desc
.Format
= dest_surface
->desc
.Format
;
1125 desc
.Usage
= D3DUSAGE_RENDERTARGET
;
1126 hr
= NineSurface9_new(pDevice
, NineUnknown(This
), temp_resource
, NULL
, 0,
1127 0, 0, &desc
, &temp_surface
);
1128 pipe_resource_reference(&temp_resource
, NULL
);
1130 DBG("Failed to create temp FrontBuffer surface.\n");
1134 ID3DPresent_FrontBufferCopy(This
->present
, temp_handle
);
1136 NineSurface9_CopyDefaultToMem(dest_surface
, temp_surface
);
1138 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, temp_handle
);
1139 NineUnknown_Destroy(NineUnknown(temp_surface
));
1145 NineSwapChain9_GetBackBuffer( struct NineSwapChain9
*This
,
1147 D3DBACKBUFFER_TYPE Type
,
1148 IDirect3DSurface9
**ppBackBuffer
)
1150 DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
1151 This
, iBackBuffer
, Type
, ppBackBuffer
);
1152 (void)user_error(Type
== D3DBACKBUFFER_TYPE_MONO
);
1153 /* don't touch ppBackBuffer on error */
1154 user_assert(ppBackBuffer
!= NULL
, D3DERR_INVALIDCALL
);
1155 user_assert(iBackBuffer
< This
->params
.BackBufferCount
, D3DERR_INVALIDCALL
);
1157 NineUnknown_AddRef(NineUnknown(This
->buffers
[iBackBuffer
]));
1158 *ppBackBuffer
= (IDirect3DSurface9
*)This
->buffers
[iBackBuffer
];
1163 NineSwapChain9_GetRasterStatus( struct NineSwapChain9
*This
,
1164 D3DRASTER_STATUS
*pRasterStatus
)
1166 DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
1167 This
, pRasterStatus
);
1168 user_assert(pRasterStatus
!= NULL
, E_POINTER
);
1169 return ID3DPresent_GetRasterStatus(This
->present
, pRasterStatus
);
1173 NineSwapChain9_GetDisplayMode( struct NineSwapChain9
*This
,
1174 D3DDISPLAYMODE
*pMode
)
1176 D3DDISPLAYMODEEX mode
;
1177 D3DDISPLAYROTATION rot
;
1180 DBG("GetDisplayMode: This=%p pMode=%p\n",
1182 user_assert(pMode
!= NULL
, E_POINTER
);
1184 hr
= ID3DPresent_GetDisplayMode(This
->present
, &mode
, &rot
);
1185 if (SUCCEEDED(hr
)) {
1186 pMode
->Width
= mode
.Width
;
1187 pMode
->Height
= mode
.Height
;
1188 pMode
->RefreshRate
= mode
.RefreshRate
;
1189 pMode
->Format
= mode
.Format
;
1195 NineSwapChain9_GetPresentParameters( struct NineSwapChain9
*This
,
1196 D3DPRESENT_PARAMETERS
*pPresentationParameters
)
1198 DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
1199 This
, pPresentationParameters
);
1200 user_assert(pPresentationParameters
!= NULL
, E_POINTER
);
1201 *pPresentationParameters
= This
->params
;
1205 IDirect3DSwapChain9Vtbl NineSwapChain9_vtable
= {
1206 (void *)NineUnknown_QueryInterface
,
1207 (void *)NineUnknown_AddRef
,
1208 (void *)NineUnknown_Release
,
1209 (void *)NineSwapChain9_Present
,
1210 (void *)NineSwapChain9_GetFrontBufferData
,
1211 (void *)NineSwapChain9_GetBackBuffer
,
1212 (void *)NineSwapChain9_GetRasterStatus
,
1213 (void *)NineSwapChain9_GetDisplayMode
,
1214 (void *)NineUnknown_GetDevice
, /* actually part of SwapChain9 iface */
1215 (void *)NineSwapChain9_GetPresentParameters
1218 static const GUID
*NineSwapChain9_IIDs
[] = {
1219 &IID_IDirect3DSwapChain9
,
1225 NineSwapChain9_new( struct NineDevice9
*pDevice
,
1227 ID3DPresent
*pPresent
,
1228 D3DPRESENT_PARAMETERS
*pPresentationParameters
,
1229 struct d3dadapter9_context
*pCTX
,
1231 struct NineSwapChain9
**ppOut
)
1233 NINE_DEVICE_CHILD_NEW(SwapChain9
, ppOut
, pDevice
, /* args */
1234 implicit
, pPresent
, pPresentationParameters
,
1235 pCTX
, hFocusWindow
, NULL
);
1239 NineSwapChain9_GetOccluded( struct NineSwapChain9
*This
)
1241 if (This
->base
.device
->minor_version_num
> 0) {
1242 return ID3DPresent_GetWindowOccluded(This
->present
);
1249 NineSwapChain9_ResolutionMismatch( struct NineSwapChain9
*This
)
1251 if (This
->base
.device
->minor_version_num
> 1) {
1252 return ID3DPresent_ResolutionMismatch(This
->present
);
1259 NineSwapChain9_CreateThread( struct NineSwapChain9
*This
,
1263 if (This
->base
.device
->minor_version_num
> 1) {
1264 return ID3DPresent_CreateThread(This
->present
, pFuncAddress
, pParam
);
1271 NineSwapChain9_WaitForThread( struct NineSwapChain9
*This
,
1274 if (This
->base
.device
->minor_version_num
> 1) {
1275 (void) ID3DPresent_WaitForThread(This
->present
, thread
);
1280 NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9
*This
,
1281 D3DPRESENT_PARAMETERS
*pParams
)
1283 int count
= pParams
->BackBufferCount
;
1285 /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
1286 * Here we don't get back the initial content of the screen. To emulate the behaviour
1287 * we allocate an additional buffer */
1288 if (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
)
1290 /* With DISCARD, as there is no guarantee about the buffer contents, we can use
1291 * an arbitrary number of buffers */
1292 if (pParams
->SwapEffect
== D3DSWAPEFFECT_DISCARD
) {
1293 /* thread_submit's can have maximum count or This->actx->throttling_value + 1
1294 * frames in flight being rendered and not shown.
1295 * Do not let count decrease that number */
1296 if (This
->actx
->thread_submit
&& count
< This
->desired_fences
)
1297 count
= This
->desired_fences
;
1298 /* When we enable AllowDISCARDDelayedRelease, we must ensure
1299 * to have at least 4 buffers to meet INTERVAL_IMMEDIATE,
1300 * since the display server/compositor can hold 3 buffers
1301 * without releasing them:
1302 * . Buffer on screen.
1303 * . Buffer scheduled kernel side to be next on screen.
1304 * . Last buffer sent. */
1305 if (This
->base
.device
->minor_version_num
> 2 &&
1306 This
->actx
->discard_delayed_release
&&
1307 pParams
->PresentationInterval
== D3DPRESENT_INTERVAL_IMMEDIATE
) {
1308 if (This
->actx
->thread_submit
&& count
< 4)
1310 /* When thread_submit is not used, 5 buffers are actually needed,
1311 * because in case a pageflip is missed because rendering wasn't finished,
1312 * the Xserver will hold 4 buffers. */
1313 else if (!This
->actx
->thread_submit
&& count
< 5)