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_inlines.h"
32 #include "util/u_surface.h"
33 #include "hud/hud_context.h"
34 #include "state_tracker/drm_driver.h"
36 #include "threadpool.h"
38 #define DBG_CHANNEL DBG_SWAPCHAIN
40 #define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
43 NineSwapChain9_ctor( struct NineSwapChain9
*This
,
44 struct NineUnknownParams
*pParams
,
46 ID3DPresent
*pPresent
,
47 D3DPRESENT_PARAMETERS
*pPresentationParameters
,
48 struct d3dadapter9_context
*pCTX
,
50 D3DDISPLAYMODEEX
*mode
)
54 DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
55 This
, pParams
->device
, pPresent
, pCTX
, hFocusWindow
);
57 hr
= NineUnknown_ctor(&This
->base
, pParams
);
61 This
->screen
= NineDevice9_GetScreen(This
->base
.device
);
62 This
->implicit
= implicit
;
64 This
->present
= pPresent
;
67 ID3DPresent_AddRef(pPresent
);
68 if (!This
->actx
->thread_submit
&&
69 This
->base
.device
->minor_version_num
> 2) {
70 D3DPRESENT_PARAMETERS2 params2
;
72 memset(¶ms2
, 0, sizeof(D3DPRESENT_PARAMETERS2
));
73 params2
.AllowDISCARDDelayedRelease
= This
->actx
->discard_delayed_release
;
74 params2
.TearFreeDISCARD
= This
->actx
->tearfree_discard
;
75 ID3DPresent_SetPresentParameters2(pPresent
, ¶ms2
);
78 if (!pPresentationParameters
->hDeviceWindow
)
79 pPresentationParameters
->hDeviceWindow
= hFocusWindow
;
81 This
->rendering_done
= FALSE
;
83 return NineSwapChain9_Resize(This
, pPresentationParameters
, mode
);
86 static D3DWindowBuffer
*
87 D3DWindowBuffer_create(struct NineSwapChain9
*This
,
88 struct pipe_resource
*resource
,
90 int for_frontbuffer_reading
)
93 struct pipe_context
*pipe
= nine_context_get_pipe_acquire(This
->base
.device
);
94 struct winsys_handle whandle
;
98 memset(&whandle
, 0, sizeof(whandle
));
99 whandle
.type
= DRM_API_HANDLE_TYPE_FD
;
100 This
->screen
->resource_get_handle(This
->screen
, pipe
, resource
,
102 for_frontbuffer_reading
?
103 PIPE_HANDLE_USAGE_WRITE
:
104 PIPE_HANDLE_USAGE_EXPLICIT_FLUSH
|
105 PIPE_HANDLE_USAGE_READ
);
106 nine_context_get_pipe_release(This
->base
.device
);
107 stride
= whandle
.stride
;
108 dmaBufFd
= whandle
.handle
;
109 hr
= ID3DPresent_NewD3DWindowBufferFromDmaBuf(This
->present
,
117 assert (SUCCEEDED(hr
));
120 ERR("Failed to create new D3DWindowBufferFromDmaBuf\n");
127 NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9
*This
,
128 D3DPRESENT_PARAMETERS
*pParams
);
131 NineSwapChain9_Resize( struct NineSwapChain9
*This
,
132 D3DPRESENT_PARAMETERS
*pParams
,
133 D3DDISPLAYMODEEX
*mode
)
135 struct NineDevice9
*pDevice
= This
->base
.device
;
136 D3DSURFACE_DESC desc
;
138 struct pipe_resource
*resource
, tmplt
;
140 BOOL has_present_buffers
= FALSE
;
142 unsigned i
, oldBufferCount
, newBufferCount
;
143 D3DMULTISAMPLE_TYPE multisample_type
;
145 DBG("This=%p pParams=%p\n", This
, pParams
);
146 user_assert(pParams
!= NULL
, E_POINTER
);
147 user_assert(pParams
->SwapEffect
, D3DERR_INVALIDCALL
);
148 user_assert((pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
) ||
149 (pParams
->BackBufferCount
<= 1), D3DERR_INVALIDCALL
);
150 user_assert(pDevice
->ex
|| pParams
->BackBufferCount
<=
151 D3DPRESENT_BACK_BUFFERS_MAX
, D3DERR_INVALIDCALL
);
152 user_assert(!pDevice
->ex
|| pParams
->BackBufferCount
<=
153 D3DPRESENT_BACK_BUFFERS_MAX_EX
, D3DERR_INVALIDCALL
);
154 user_assert(pDevice
->ex
||
155 (pParams
->SwapEffect
== D3DSWAPEFFECT_FLIP
) ||
156 (pParams
->SwapEffect
== D3DSWAPEFFECT_COPY
) ||
157 (pParams
->SwapEffect
== D3DSWAPEFFECT_DISCARD
), D3DERR_INVALIDCALL
);
160 "BackBufferWidth: %u\n"
161 "BackBufferHeight: %u\n"
162 "BackBufferFormat: %s\n"
163 "BackBufferCount: %u\n"
164 "MultiSampleType: %u\n"
165 "MultiSampleQuality: %u\n"
167 "hDeviceWindow: %p\n"
169 "EnableAutoDepthStencil: %i\n"
170 "AutoDepthStencilFormat: %s\n"
172 "FullScreen_RefreshRateInHz: %u\n"
173 "PresentationInterval: %x\n", pParams
,
174 pParams
->BackBufferWidth
, pParams
->BackBufferHeight
,
175 d3dformat_to_string(pParams
->BackBufferFormat
),
176 pParams
->BackBufferCount
,
177 pParams
->MultiSampleType
, pParams
->MultiSampleQuality
,
178 pParams
->SwapEffect
, pParams
->hDeviceWindow
, pParams
->Windowed
,
179 pParams
->EnableAutoDepthStencil
,
180 d3dformat_to_string(pParams
->AutoDepthStencilFormat
),
181 nine_D3DPRESENTFLAG_to_str(pParams
->Flags
),
182 pParams
->FullScreen_RefreshRateInHz
,
183 pParams
->PresentationInterval
);
185 if (pParams
->BackBufferCount
== 0) {
186 pParams
->BackBufferCount
= 1;
189 if (pParams
->BackBufferFormat
== D3DFMT_UNKNOWN
) {
190 pParams
->BackBufferFormat
= D3DFMT_A8R8G8B8
;
193 This
->desired_fences
= This
->actx
->throttling
? This
->actx
->throttling_value
+ 1 : 0;
194 /* +1 because we add the fence of the current buffer before popping an old one */
195 if (This
->desired_fences
> DRI_SWAP_FENCES_MAX
)
196 This
->desired_fences
= DRI_SWAP_FENCES_MAX
;
198 if (This
->actx
->vblank_mode
== 0)
199 pParams
->PresentationInterval
= D3DPRESENT_INTERVAL_IMMEDIATE
;
200 else if (This
->actx
->vblank_mode
== 3)
201 pParams
->PresentationInterval
= D3DPRESENT_INTERVAL_ONE
;
203 if (mode
&& This
->mode
) {
204 *(This
->mode
) = *mode
;
206 This
->mode
= malloc(sizeof(D3DDISPLAYMODEEX
));
207 memcpy(This
->mode
, mode
, sizeof(D3DDISPLAYMODEEX
));
213 /* Note: It is the role of the backend to fill if necessary
214 * BackBufferWidth and BackBufferHeight */
215 hr
= ID3DPresent_SetPresentParameters(This
->present
, pParams
, This
->mode
);
219 oldBufferCount
= This
->num_back_buffers
;
220 newBufferCount
= NineSwapChain9_GetBackBufferCountForParams(This
, pParams
);
222 multisample_type
= pParams
->MultiSampleType
;
224 /* Map MultiSampleQuality to MultiSampleType */
225 hr
= d3dmultisample_type_check(This
->screen
, pParams
->BackBufferFormat
,
227 pParams
->MultiSampleQuality
,
233 pf
= d3d9_to_pipe_format_checked(This
->screen
, pParams
->BackBufferFormat
,
234 PIPE_TEXTURE_2D
, multisample_type
,
235 PIPE_BIND_RENDER_TARGET
, FALSE
, FALSE
);
237 if (This
->actx
->linear_framebuffer
||
238 (pf
!= PIPE_FORMAT_B8G8R8X8_UNORM
&&
239 pf
!= PIPE_FORMAT_B8G8R8A8_UNORM
) ||
240 pParams
->SwapEffect
!= D3DSWAPEFFECT_DISCARD
||
241 multisample_type
>= 2 ||
242 (This
->actx
->ref
&& This
->actx
->ref
== This
->screen
))
243 has_present_buffers
= TRUE
;
245 /* Note: the buffer depth has to match the window depth.
246 * In practice, ARGB buffers can be used with windows
247 * of depth 24. Windows of depth 32 are extremely rare.
248 * So even if the buffer is ARGB, say it is depth 24.
249 * It is common practice, for example that's how
250 * glamor implements depth 24.
251 * TODO: handle windows with other depths. Not possible in the short term.
252 * For example 16 bits.*/
255 memset(&tmplt
, 0, sizeof(tmplt
));
256 tmplt
.target
= PIPE_TEXTURE_2D
;
257 tmplt
.width0
= pParams
->BackBufferWidth
;
258 tmplt
.height0
= pParams
->BackBufferHeight
;
260 tmplt
.last_level
= 0;
261 tmplt
.array_size
= 1;
262 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
265 desc
.Type
= D3DRTYPE_SURFACE
;
266 desc
.Pool
= D3DPOOL_DEFAULT
;
267 desc
.MultiSampleType
= pParams
->MultiSampleType
;
268 desc
.MultiSampleQuality
= pParams
->MultiSampleQuality
;
269 desc
.Width
= pParams
->BackBufferWidth
;
270 desc
.Height
= pParams
->BackBufferHeight
;
272 for (i
= 0; i
< oldBufferCount
; i
++) {
274 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[i
]));
276 memset(This
->tasks
, 0, sizeof(This
->tasks
));
279 _mesa_threadpool_destroy(This
, This
->pool
);
282 This
->enable_threadpool
= This
->actx
->thread_submit
&& (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
);
283 if (This
->enable_threadpool
)
284 This
->pool
= _mesa_threadpool_create(This
);
286 This
->enable_threadpool
= FALSE
;
288 for (i
= 0; i
< oldBufferCount
; i
++) {
289 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, This
->present_handles
[i
]);
290 This
->present_handles
[i
] = NULL
;
291 if (This
->present_buffers
[i
])
292 pipe_resource_reference(&(This
->present_buffers
[i
]), NULL
);
295 if (newBufferCount
!= oldBufferCount
) {
296 for (i
= newBufferCount
; i
< oldBufferCount
;
298 NineUnknown_Detach(NineUnknown(This
->buffers
[i
]));
300 for (i
= oldBufferCount
; i
< newBufferCount
; ++i
) {
301 This
->buffers
[i
] = NULL
;
302 This
->present_handles
[i
] = NULL
;
305 This
->num_back_buffers
= newBufferCount
;
307 for (i
= 0; i
< newBufferCount
; ++i
) {
308 tmplt
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_RENDER_TARGET
;
309 tmplt
.nr_samples
= multisample_type
;
310 if (!has_present_buffers
)
311 tmplt
.bind
|= NINE_BIND_PRESENTBUFFER_FLAGS
;
312 tmplt
.format
= d3d9_to_pipe_format_checked(This
->screen
,
313 pParams
->BackBufferFormat
,
316 tmplt
.bind
, FALSE
, FALSE
);
317 if (tmplt
.format
== PIPE_FORMAT_NONE
)
318 return D3DERR_INVALIDCALL
;
319 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
321 DBG("Failed to create pipe_resource.\n");
322 return D3DERR_OUTOFVIDEOMEMORY
;
324 if (pParams
->Flags
& D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
)
325 resource
->flags
|= NINE_RESOURCE_FLAG_LOCKABLE
;
326 if (This
->buffers
[i
]) {
327 NineSurface9_SetMultiSampleType(This
->buffers
[i
], desc
.MultiSampleType
);
328 NineSurface9_SetResourceResize(This
->buffers
[i
], resource
);
329 if (has_present_buffers
)
330 pipe_resource_reference(&resource
, NULL
);
332 desc
.Format
= pParams
->BackBufferFormat
;
333 desc
.Usage
= D3DUSAGE_RENDERTARGET
;
334 hr
= NineSurface9_new(pDevice
, NineUnknown(This
), resource
, NULL
, 0,
335 0, 0, &desc
, &This
->buffers
[i
]);
336 if (has_present_buffers
)
337 pipe_resource_reference(&resource
, NULL
);
339 DBG("Failed to create RT surface.\n");
342 This
->buffers
[i
]->base
.base
.forward
= FALSE
;
344 if (has_present_buffers
) {
345 tmplt
.format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
346 tmplt
.bind
= NINE_BIND_PRESENTBUFFER_FLAGS
;
347 tmplt
.nr_samples
= 0;
348 if (This
->actx
->linear_framebuffer
)
349 tmplt
.bind
|= PIPE_BIND_LINEAR
;
350 if (pParams
->SwapEffect
!= D3DSWAPEFFECT_DISCARD
)
351 tmplt
.bind
|= PIPE_BIND_RENDER_TARGET
;
352 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
353 pipe_resource_reference(&(This
->present_buffers
[i
]), resource
);
355 This
->present_handles
[i
] = D3DWindowBuffer_create(This
, resource
, depth
, false);
356 pipe_resource_reference(&resource
, NULL
);
357 if (!This
->present_handles
[i
]) {
358 return D3DERR_DRIVERINTERNALERROR
;
361 if (pParams
->EnableAutoDepthStencil
) {
362 tmplt
.bind
= d3d9_get_pipe_depth_format_bindings(pParams
->AutoDepthStencilFormat
);
363 tmplt
.nr_samples
= multisample_type
;
364 tmplt
.format
= d3d9_to_pipe_format_checked(This
->screen
,
365 pParams
->AutoDepthStencilFormat
,
371 if (tmplt
.format
== PIPE_FORMAT_NONE
)
372 return D3DERR_INVALIDCALL
;
375 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
377 DBG("Failed to create pipe_resource for depth buffer.\n");
378 return D3DERR_OUTOFVIDEOMEMORY
;
381 NineSurface9_SetMultiSampleType(This
->zsbuf
, desc
.MultiSampleType
);
382 NineSurface9_SetResourceResize(This
->zsbuf
, resource
);
383 pipe_resource_reference(&resource
, NULL
);
385 hr
= NineDevice9_CreateDepthStencilSurface(pDevice
,
386 pParams
->BackBufferWidth
,
387 pParams
->BackBufferHeight
,
388 pParams
->AutoDepthStencilFormat
,
389 pParams
->MultiSampleType
,
390 pParams
->MultiSampleQuality
,
392 (IDirect3DSurface9
**)&This
->zsbuf
,
395 DBG("Failed to create ZS surface.\n");
398 NineUnknown_ConvertRefToBind(NineUnknown(This
->zsbuf
));
402 This
->params
= *pParams
;
407 /* Throttling: code adapted from the dri state tracker */
410 * swap_fences_pop_front - pull a fence from the throttle queue
412 * If the throttle queue is filled to the desired number of fences,
413 * pull fences off the queue until the number is less than the desired
414 * number of fences, and return the last fence pulled.
416 static struct pipe_fence_handle
*
417 swap_fences_pop_front(struct NineSwapChain9
*This
)
419 struct pipe_screen
*screen
= This
->screen
;
420 struct pipe_fence_handle
*fence
= NULL
;
422 if (This
->desired_fences
== 0)
425 if (This
->cur_fences
>= This
->desired_fences
) {
426 screen
->fence_reference(screen
, &fence
, This
->swap_fences
[This
->tail
]);
427 screen
->fence_reference(screen
, &This
->swap_fences
[This
->tail
++], NULL
);
428 This
->tail
&= DRI_SWAP_FENCES_MASK
;
436 * swap_fences_see_front - same than swap_fences_pop_front without
441 static struct pipe_fence_handle
*
442 swap_fences_see_front(struct NineSwapChain9
*This
)
444 struct pipe_screen
*screen
= This
->screen
;
445 struct pipe_fence_handle
*fence
= NULL
;
447 if (This
->desired_fences
== 0)
450 if (This
->cur_fences
>= This
->desired_fences
) {
451 screen
->fence_reference(screen
, &fence
, This
->swap_fences
[This
->tail
]);
458 * swap_fences_push_back - push a fence onto the throttle queue at the back
460 * push a fence onto the throttle queue and pull fences of the queue
461 * so that the desired number of fences are on the queue.
464 swap_fences_push_back(struct NineSwapChain9
*This
,
465 struct pipe_fence_handle
*fence
)
467 struct pipe_screen
*screen
= This
->screen
;
469 if (!fence
|| This
->desired_fences
== 0)
472 while(This
->cur_fences
== This
->desired_fences
)
473 swap_fences_pop_front(This
);
476 screen
->fence_reference(screen
, &This
->swap_fences
[This
->head
++],
478 This
->head
&= DRI_SWAP_FENCES_MASK
;
483 * swap_fences_unref - empty the throttle queue
485 * pulls fences of the throttle queue until it is empty.
488 swap_fences_unref(struct NineSwapChain9
*This
)
490 struct pipe_screen
*screen
= This
->screen
;
492 while(This
->cur_fences
) {
493 screen
->fence_reference(screen
, &This
->swap_fences
[This
->tail
++], NULL
);
494 This
->tail
&= DRI_SWAP_FENCES_MASK
;
500 NineSwapChain9_dtor( struct NineSwapChain9
*This
)
504 DBG("This=%p\n", This
);
507 _mesa_threadpool_destroy(This
, This
->pool
);
509 for (i
= 0; i
< This
->num_back_buffers
; i
++) {
510 if (This
->buffers
[i
])
511 NineUnknown_Detach(NineUnknown(This
->buffers
[i
]));
512 if (This
->present_handles
[i
])
513 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, This
->present_handles
[i
]);
514 if (This
->present_buffers
[i
])
515 pipe_resource_reference(&(This
->present_buffers
[i
]), NULL
);
518 NineUnknown_Unbind(NineUnknown(This
->zsbuf
));
521 ID3DPresent_Release(This
->present
);
523 swap_fences_unref(This
);
524 NineUnknown_dtor(&This
->base
);
528 create_present_buffer( struct NineSwapChain9
*This
,
529 unsigned int width
, unsigned int height
,
530 struct pipe_resource
**resource
,
531 D3DWindowBuffer
**present_handle
)
533 struct pipe_resource tmplt
;
535 memset(&tmplt
, 0, sizeof(tmplt
));
536 tmplt
.target
= PIPE_TEXTURE_2D
;
537 tmplt
.width0
= width
;
538 tmplt
.height0
= height
;
540 tmplt
.last_level
= 0;
541 tmplt
.array_size
= 1;
542 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
544 tmplt
.format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
545 tmplt
.bind
= NINE_BIND_BACKBUFFER_FLAGS
|
546 NINE_BIND_PRESENTBUFFER_FLAGS
;
547 tmplt
.nr_samples
= 0;
548 if (This
->actx
->linear_framebuffer
)
549 tmplt
.bind
|= PIPE_BIND_LINEAR
;
550 *resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
552 *present_handle
= D3DWindowBuffer_create(This
, *resource
, 24, true);
554 if (!*present_handle
) {
555 pipe_resource_reference(resource
, NULL
);
560 handle_draw_cursor_and_hud( struct NineSwapChain9
*This
, struct pipe_resource
*resource
)
562 struct NineDevice9
*device
= This
->base
.device
;
563 struct pipe_blit_info blit
;
564 struct pipe_context
*pipe
;
566 if (device
->cursor
.software
&& device
->cursor
.visible
&& device
->cursor
.w
) {
567 memset(&blit
, 0, sizeof(blit
));
568 blit
.src
.resource
= device
->cursor
.image
;
570 blit
.src
.format
= device
->cursor
.image
->format
;
574 blit
.src
.box
.depth
= 1;
575 blit
.src
.box
.width
= device
->cursor
.w
;
576 blit
.src
.box
.height
= device
->cursor
.h
;
578 blit
.dst
.resource
= resource
;
580 blit
.dst
.format
= resource
->format
;
582 blit
.dst
.box
.depth
= 1;
584 blit
.mask
= PIPE_MASK_RGBA
;
585 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
586 blit
.scissor_enable
= FALSE
;
588 /* NOTE: blit messes up when box.x + box.width < 0, fix driver
589 * NOTE2: device->cursor.pos contains coordinates relative to the screen.
590 * This happens to be also the position of the cursor when we are fullscreen.
591 * We don't use sw cursor for Windowed mode */
592 blit
.dst
.box
.x
= MAX2(device
->cursor
.pos
.x
, 0) - device
->cursor
.hotspot
.x
;
593 blit
.dst
.box
.y
= MAX2(device
->cursor
.pos
.y
, 0) - device
->cursor
.hotspot
.y
;
594 blit
.dst
.box
.width
= blit
.src
.box
.width
;
595 blit
.dst
.box
.height
= blit
.src
.box
.height
;
597 DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
598 blit
.src
.box
.width
, blit
.src
.box
.height
,
599 blit
.dst
.box
.x
, blit
.dst
.box
.y
);
601 blit
.alpha_blend
= TRUE
;
602 pipe
= NineDevice9_GetPipe(This
->base
.device
);
603 pipe
->blit(pipe
, &blit
);
606 if (device
->hud
&& resource
) {
607 /* Implicit use of context pipe */
608 (void)NineDevice9_GetPipe(This
->base
.device
);
609 hud_draw(device
->hud
, resource
); /* XXX: no offset */
610 /* HUD doesn't clobber stipple */
611 nine_state_restore_non_cso(device
);
615 struct end_present_struct
{
616 struct pipe_screen
*screen
;
617 struct pipe_fence_handle
*fence_to_wait
;
618 ID3DPresent
*present
;
619 D3DWindowBuffer
*present_handle
;
620 HWND hDestWindowOverride
;
623 static void work_present(void *data
)
625 struct end_present_struct
*work
= data
;
626 if (work
->fence_to_wait
) {
627 (void) work
->screen
->fence_finish(work
->screen
, NULL
, work
->fence_to_wait
, PIPE_TIMEOUT_INFINITE
);
628 work
->screen
->fence_reference(work
->screen
, &(work
->fence_to_wait
), NULL
);
630 ID3DPresent_PresentBuffer(work
->present
, work
->present_handle
, work
->hDestWindowOverride
, NULL
, NULL
, NULL
, 0);
634 static void pend_present(struct NineSwapChain9
*This
,
635 HWND hDestWindowOverride
)
637 struct end_present_struct
*work
= calloc(1, sizeof(struct end_present_struct
));
639 work
->screen
= This
->screen
;
640 work
->fence_to_wait
= swap_fences_pop_front(This
);
641 work
->present
= This
->present
;
642 work
->present_handle
= This
->present_handles
[0];
643 work
->hDestWindowOverride
= hDestWindowOverride
;
644 This
->tasks
[0] = _mesa_threadpool_queue_task(This
->pool
, work_present
, work
);
649 static inline HRESULT
650 present( struct NineSwapChain9
*This
,
651 const RECT
*pSourceRect
,
652 const RECT
*pDestRect
,
653 HWND hDestWindowOverride
,
654 const RGNDATA
*pDirtyRegion
,
657 struct pipe_context
*pipe
;
658 struct pipe_resource
*resource
;
659 struct pipe_fence_handle
*fence
;
661 struct pipe_blit_info blit
;
663 DBG("present: This=%p pSourceRect=%p pDestRect=%p "
664 "pDirtyRegion=%p hDestWindowOverride=%p"
665 "dwFlags=%d resource=%p\n",
666 This
, pSourceRect
, pDestRect
, pDirtyRegion
,
667 hDestWindowOverride
, (int)dwFlags
, This
->buffers
[0]->base
.resource
);
670 DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
671 pSourceRect
->left
, pSourceRect
->right
,
672 pSourceRect
->top
, pSourceRect
->bottom
);
674 DBG("pDestRect = (%u..%u)x(%u..%u)\n",
675 pDestRect
->left
, pDestRect
->right
,
676 pDestRect
->top
, pDestRect
->bottom
);
678 /* TODO: in the case the source and destination rect have different size:
679 * We need to allocate a new buffer, and do a blit to it to resize.
680 * We can't use the present_buffer for that since when we created it,
681 * we couldn't guess which size would have been needed.
682 * If pDestRect or pSourceRect is null, we have to check the sizes
683 * from the source size, and the destination window size.
684 * In this case, either resize rngdata, or pass NULL instead
686 /* Note: This->buffers[0]->level should always be 0 */
688 if (This
->rendering_done
)
689 goto bypass_rendering
;
691 resource
= This
->buffers
[0]->base
.resource
;
693 if (This
->params
.SwapEffect
== D3DSWAPEFFECT_DISCARD
)
694 handle_draw_cursor_and_hud(This
, resource
);
696 pipe
= NineDevice9_GetPipe(This
->base
.device
);
698 if (This
->present_buffers
[0]) {
699 memset(&blit
, 0, sizeof(blit
));
700 blit
.src
.resource
= resource
;
702 blit
.src
.format
= resource
->format
;
704 blit
.src
.box
.depth
= 1;
707 blit
.src
.box
.width
= resource
->width0
;
708 blit
.src
.box
.height
= resource
->height0
;
710 resource
= This
->present_buffers
[0];
712 blit
.dst
.resource
= resource
;
714 blit
.dst
.format
= resource
->format
;
716 blit
.dst
.box
.depth
= 1;
719 blit
.dst
.box
.width
= resource
->width0
;
720 blit
.dst
.box
.height
= resource
->height0
;
722 blit
.mask
= PIPE_MASK_RGBA
;
723 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
724 blit
.scissor_enable
= FALSE
;
725 blit
.alpha_blend
= FALSE
;
727 pipe
->blit(pipe
, &blit
);
730 /* The resource we present has to resolve fast clears
731 * if needed (and other things) */
732 pipe
->flush_resource(pipe
, resource
);
734 if (This
->params
.SwapEffect
!= D3DSWAPEFFECT_DISCARD
)
735 handle_draw_cursor_and_hud(This
, resource
);
738 pipe
->flush(pipe
, &fence
, PIPE_FLUSH_END_OF_FRAME
);
740 swap_fences_push_back(This
, fence
);
741 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
744 This
->rendering_done
= TRUE
;
747 if (dwFlags
& D3DPRESENT_DONOTWAIT
) {
749 BOOL still_draw
= FALSE
;
750 fence
= swap_fences_see_front(This
);
752 still_draw
= !This
->screen
->fence_finish(This
->screen
, NULL
, fence
, 0);
753 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
756 return D3DERR_WASSTILLDRAWING
;
759 if (!This
->enable_threadpool
) {
761 fence
= swap_fences_pop_front(This
);
763 (void) This
->screen
->fence_finish(This
->screen
, NULL
, fence
, PIPE_TIMEOUT_INFINITE
);
764 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
767 hr
= ID3DPresent_PresentBuffer(This
->present
, This
->present_handles
[0], hDestWindowOverride
, pSourceRect
, pDestRect
, pDirtyRegion
, dwFlags
);
769 if (FAILED(hr
)) { UNTESTED(3);return hr
; }
771 pend_present(This
, hDestWindowOverride
);
773 This
->rendering_done
= FALSE
;
779 NineSwapChain9_Present( struct NineSwapChain9
*This
,
780 const RECT
*pSourceRect
,
781 const RECT
*pDestRect
,
782 HWND hDestWindowOverride
,
783 const RGNDATA
*pDirtyRegion
,
786 struct pipe_resource
*res
= NULL
;
787 D3DWindowBuffer
*handle_temp
;
788 struct threadpool_task
*task_temp
;
792 DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
793 "pDirtyRegion=%p dwFlags=%d\n",
794 This
, pSourceRect
, pDestRect
, hDestWindowOverride
,
795 pDirtyRegion
,dwFlags
);
797 if (This
->base
.device
->ex
) {
798 if (NineSwapChain9_GetOccluded(This
)) {
799 DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n");
800 return S_PRESENT_OCCLUDED
;
803 if (NineSwapChain9_GetOccluded(This
) ||
804 NineSwapChain9_ResolutionMismatch(This
)) {
805 This
->base
.device
->device_needs_reset
= TRUE
;
807 if (This
->base
.device
->device_needs_reset
) {
808 DBG("Device is lost. Returning D3DERR_DEVICELOST.\n");
809 return D3DERR_DEVICELOST
;
813 nine_csmt_process(This
->base
.device
);
815 hr
= present(This
, pSourceRect
, pDestRect
,
816 hDestWindowOverride
, pDirtyRegion
, dwFlags
);
817 if (hr
== D3DERR_WASSTILLDRAWING
)
820 if (This
->base
.device
->minor_version_num
> 2 &&
821 This
->params
.SwapEffect
== D3DSWAPEFFECT_DISCARD
&&
822 This
->params
.PresentationInterval
== D3DPRESENT_INTERVAL_IMMEDIATE
&&
823 !This
->actx
->thread_submit
) {
824 int next_buffer
= -1;
826 while (next_buffer
== -1) {
827 /* Find a free backbuffer */
828 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
829 if (ID3DPresent_IsBufferReleased(This
->present
, This
->present_handles
[i
])) {
830 DBG("Found buffer released: %d\n", i
);
835 if (next_buffer
== -1) {
836 DBG("Found no buffer released. Waiting for event\n");
837 ID3DPresent_WaitBufferReleaseEvent(This
->present
);
840 /* Switch with the released buffer */
841 pipe_resource_reference(&res
, This
->buffers
[0]->base
.resource
);
842 NineSurface9_SetResourceResize(
843 This
->buffers
[0], This
->buffers
[next_buffer
]->base
.resource
);
844 NineSurface9_SetResourceResize(
845 This
->buffers
[next_buffer
], res
);
846 pipe_resource_reference(&res
, NULL
);
848 if (This
->present_buffers
[0]) {
849 pipe_resource_reference(&res
, This
->present_buffers
[0]);
850 pipe_resource_reference(&This
->present_buffers
[0], This
->present_buffers
[next_buffer
]);
851 pipe_resource_reference(&This
->present_buffers
[next_buffer
], res
);
852 pipe_resource_reference(&res
, NULL
);
855 handle_temp
= This
->present_handles
[0];
856 This
->present_handles
[0] = This
->present_handles
[next_buffer
];
857 This
->present_handles
[next_buffer
] = handle_temp
;
859 /* Path not yet compatible with thread_submit */
860 assert(!This
->tasks
[0] && !This
->tasks
[next_buffer
]);
862 switch (This
->params
.SwapEffect
) {
863 case D3DSWAPEFFECT_OVERLAY
: /* Not implemented, fallback to FLIP */
864 case D3DSWAPEFFECT_FLIPEX
: /* Allows optimizations over FLIP for windowed mode. */
865 case D3DSWAPEFFECT_DISCARD
: /* Allows optimizations over FLIP */
866 case D3DSWAPEFFECT_FLIP
:
867 /* rotate the queue */
868 pipe_resource_reference(&res
, This
->buffers
[0]->base
.resource
);
869 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
870 NineSurface9_SetResourceResize(This
->buffers
[i
- 1],
871 This
->buffers
[i
]->base
.resource
);
873 NineSurface9_SetResourceResize(
874 This
->buffers
[This
->num_back_buffers
- 1], res
);
875 pipe_resource_reference(&res
, NULL
);
877 if (This
->present_buffers
[0]) {
878 pipe_resource_reference(&res
, This
->present_buffers
[0]);
879 for (i
= 1; i
< This
->num_back_buffers
; i
++)
880 pipe_resource_reference(&(This
->present_buffers
[i
-1]), This
->present_buffers
[i
]);
881 pipe_resource_reference(&(This
->present_buffers
[This
->num_back_buffers
- 1]), res
);
882 pipe_resource_reference(&res
, NULL
);
885 handle_temp
= This
->present_handles
[0];
886 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
887 This
->present_handles
[i
-1] = This
->present_handles
[i
];
889 This
->present_handles
[This
->num_back_buffers
- 1] = handle_temp
;
890 task_temp
= This
->tasks
[0];
891 for (i
= 1; i
< This
->num_back_buffers
; i
++) {
892 This
->tasks
[i
-1] = This
->tasks
[i
];
894 This
->tasks
[This
->num_back_buffers
- 1] = task_temp
;
897 case D3DSWAPEFFECT_COPY
:
903 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[0]));
905 ID3DPresent_WaitBufferReleased(This
->present
, This
->present_handles
[0]);
908 This
->base
.device
->context
.changed
.group
|= NINE_STATE_FB
;
914 NineSwapChain9_GetFrontBufferData( struct NineSwapChain9
*This
,
915 IDirect3DSurface9
*pDestSurface
)
917 struct NineSurface9
*dest_surface
= NineSurface9(pDestSurface
);
918 struct NineDevice9
*pDevice
= This
->base
.device
;
919 unsigned int width
, height
;
920 struct pipe_resource
*temp_resource
;
921 struct NineSurface9
*temp_surface
;
922 D3DWindowBuffer
*temp_handle
;
923 D3DSURFACE_DESC desc
;
926 DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
929 user_assert(dest_surface
->base
.pool
== D3DPOOL_SYSTEMMEM
, D3DERR_INVALIDCALL
);
931 width
= dest_surface
->desc
.Width
;
932 height
= dest_surface
->desc
.Height
;
934 /* Note: front window size and destination size are supposed
935 * to match. However it's not very clear what should get taken in Windowed
936 * mode. It may need a fix */
937 create_present_buffer(This
, width
, height
, &temp_resource
, &temp_handle
);
939 if (!temp_resource
|| !temp_handle
) {
940 return D3DERR_INVALIDCALL
;
943 desc
.Type
= D3DRTYPE_SURFACE
;
944 desc
.Pool
= D3DPOOL_DEFAULT
;
945 desc
.MultiSampleType
= D3DMULTISAMPLE_NONE
;
946 desc
.MultiSampleQuality
= 0;
948 desc
.Height
= height
;
949 /* NineSurface9_CopyDefaultToMem needs same format. */
950 desc
.Format
= dest_surface
->desc
.Format
;
951 desc
.Usage
= D3DUSAGE_RENDERTARGET
;
952 hr
= NineSurface9_new(pDevice
, NineUnknown(This
), temp_resource
, NULL
, 0,
953 0, 0, &desc
, &temp_surface
);
954 pipe_resource_reference(&temp_resource
, NULL
);
956 DBG("Failed to create temp FrontBuffer surface.\n");
960 ID3DPresent_FrontBufferCopy(This
->present
, temp_handle
);
962 NineSurface9_CopyDefaultToMem(dest_surface
, temp_surface
);
964 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, temp_handle
);
965 NineUnknown_Destroy(NineUnknown(temp_surface
));
971 NineSwapChain9_GetBackBuffer( struct NineSwapChain9
*This
,
973 D3DBACKBUFFER_TYPE Type
,
974 IDirect3DSurface9
**ppBackBuffer
)
976 DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
977 This
, iBackBuffer
, Type
, ppBackBuffer
);
978 (void)user_error(Type
== D3DBACKBUFFER_TYPE_MONO
);
979 /* don't touch ppBackBuffer on error */
980 user_assert(ppBackBuffer
!= NULL
, D3DERR_INVALIDCALL
);
981 user_assert(iBackBuffer
< This
->params
.BackBufferCount
, D3DERR_INVALIDCALL
);
983 NineUnknown_AddRef(NineUnknown(This
->buffers
[iBackBuffer
]));
984 *ppBackBuffer
= (IDirect3DSurface9
*)This
->buffers
[iBackBuffer
];
989 NineSwapChain9_GetRasterStatus( struct NineSwapChain9
*This
,
990 D3DRASTER_STATUS
*pRasterStatus
)
992 DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
993 This
, pRasterStatus
);
994 user_assert(pRasterStatus
!= NULL
, E_POINTER
);
995 return ID3DPresent_GetRasterStatus(This
->present
, pRasterStatus
);
999 NineSwapChain9_GetDisplayMode( struct NineSwapChain9
*This
,
1000 D3DDISPLAYMODE
*pMode
)
1002 D3DDISPLAYMODEEX mode
;
1003 D3DDISPLAYROTATION rot
;
1006 DBG("GetDisplayMode: This=%p pMode=%p\n",
1008 user_assert(pMode
!= NULL
, E_POINTER
);
1010 hr
= ID3DPresent_GetDisplayMode(This
->present
, &mode
, &rot
);
1011 if (SUCCEEDED(hr
)) {
1012 pMode
->Width
= mode
.Width
;
1013 pMode
->Height
= mode
.Height
;
1014 pMode
->RefreshRate
= mode
.RefreshRate
;
1015 pMode
->Format
= mode
.Format
;
1021 NineSwapChain9_GetPresentParameters( struct NineSwapChain9
*This
,
1022 D3DPRESENT_PARAMETERS
*pPresentationParameters
)
1024 DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
1025 This
, pPresentationParameters
);
1026 user_assert(pPresentationParameters
!= NULL
, E_POINTER
);
1027 *pPresentationParameters
= This
->params
;
1031 IDirect3DSwapChain9Vtbl NineSwapChain9_vtable
= {
1032 (void *)NineUnknown_QueryInterface
,
1033 (void *)NineUnknown_AddRef
,
1034 (void *)NineUnknown_Release
,
1035 (void *)NineSwapChain9_Present
,
1036 (void *)NineSwapChain9_GetFrontBufferData
,
1037 (void *)NineSwapChain9_GetBackBuffer
,
1038 (void *)NineSwapChain9_GetRasterStatus
,
1039 (void *)NineSwapChain9_GetDisplayMode
,
1040 (void *)NineUnknown_GetDevice
, /* actually part of SwapChain9 iface */
1041 (void *)NineSwapChain9_GetPresentParameters
1044 static const GUID
*NineSwapChain9_IIDs
[] = {
1045 &IID_IDirect3DSwapChain9
,
1051 NineSwapChain9_new( struct NineDevice9
*pDevice
,
1053 ID3DPresent
*pPresent
,
1054 D3DPRESENT_PARAMETERS
*pPresentationParameters
,
1055 struct d3dadapter9_context
*pCTX
,
1057 struct NineSwapChain9
**ppOut
)
1059 NINE_DEVICE_CHILD_NEW(SwapChain9
, ppOut
, pDevice
, /* args */
1060 implicit
, pPresent
, pPresentationParameters
,
1061 pCTX
, hFocusWindow
, NULL
);
1065 NineSwapChain9_GetOccluded( struct NineSwapChain9
*This
)
1067 if (This
->base
.device
->minor_version_num
> 0) {
1068 return ID3DPresent_GetWindowOccluded(This
->present
);
1075 NineSwapChain9_ResolutionMismatch( struct NineSwapChain9
*This
)
1077 if (This
->base
.device
->minor_version_num
> 1) {
1078 return ID3DPresent_ResolutionMismatch(This
->present
);
1085 NineSwapChain9_CreateThread( struct NineSwapChain9
*This
,
1089 if (This
->base
.device
->minor_version_num
> 1) {
1090 return ID3DPresent_CreateThread(This
->present
, pFuncAddress
, pParam
);
1097 NineSwapChain9_WaitForThread( struct NineSwapChain9
*This
,
1100 if (This
->base
.device
->minor_version_num
> 1) {
1101 (void) ID3DPresent_WaitForThread(This
->present
, thread
);
1106 NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9
*This
,
1107 D3DPRESENT_PARAMETERS
*pParams
)
1109 int count
= pParams
->BackBufferCount
;
1111 /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
1112 * Here we don't get back the initial content of the screen. To emulate the behaviour
1113 * we allocate an additional buffer */
1114 if (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
)
1116 /* With DISCARD, as there is no guarantee about the buffer contents, we can use
1117 * an arbitrary number of buffers */
1118 if (pParams
->SwapEffect
== D3DSWAPEFFECT_DISCARD
) {
1119 /* thread_submit has a throttling equivalent to the throttling
1120 * with throttling_value set to count-1. Most drivers use
1121 * 2 for throttling_value. For performance use count of at least 3
1122 * for thread_submit. */
1123 if (This
->actx
->thread_submit
&& count
< 3)
1125 /* When we enable AllowDISCARDDelayedRelease, we must ensure
1126 * to have at least 4 buffers to meet INTERVAL_IMMEDIATE,
1127 * since the display server/compositor can hold 3 buffers
1128 * without releasing them:
1129 * . Buffer on screen.
1130 * . Buffer scheduled kernel side to be next on screen.
1131 * . Last buffer sent.
1132 * For some reasons, 5 buffers are actually needed, because in
1133 * case a pageflip is missed because rendering wasn't finished,
1134 * the Xserver will hold 4 buffers. */
1135 if (!This
->actx
->thread_submit
&&
1136 This
->base
.device
->minor_version_num
> 2 &&
1137 pParams
->PresentationInterval
== D3DPRESENT_INTERVAL_IMMEDIATE
&&