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
->pipe
= NineDevice9_GetPipe(This
->base
.device
);
63 This
->cso
= NineDevice9_GetCSO(This
->base
.device
);
64 This
->implicit
= implicit
;
66 This
->present
= pPresent
;
69 ID3DPresent_AddRef(pPresent
);
71 if (!pPresentationParameters
->hDeviceWindow
)
72 pPresentationParameters
->hDeviceWindow
= hFocusWindow
;
74 This
->rendering_done
= FALSE
;
76 return NineSwapChain9_Resize(This
, pPresentationParameters
, mode
);
79 static D3DWindowBuffer
*
80 D3DWindowBuffer_create(struct NineSwapChain9
*This
,
81 struct pipe_resource
*resource
,
83 int for_frontbuffer_reading
)
86 struct winsys_handle whandle
;
89 memset(&whandle
, 0, sizeof(whandle
));
90 whandle
.type
= DRM_API_HANDLE_TYPE_FD
;
91 This
->screen
->resource_get_handle(This
->screen
, resource
, &whandle
,
92 for_frontbuffer_reading
?
93 PIPE_HANDLE_USAGE_WRITE
:
94 PIPE_HANDLE_USAGE_EXPLICIT_FLUSH
|
95 PIPE_HANDLE_USAGE_READ
);
96 stride
= whandle
.stride
;
97 dmaBufFd
= whandle
.handle
;
98 ID3DPresent_NewD3DWindowBufferFromDmaBuf(This
->present
,
110 NineSwapChain9_Resize( struct NineSwapChain9
*This
,
111 D3DPRESENT_PARAMETERS
*pParams
,
112 D3DDISPLAYMODEEX
*mode
)
114 struct NineDevice9
*pDevice
= This
->base
.device
;
115 struct NineSurface9
**bufs
;
116 D3DSURFACE_DESC desc
;
118 struct pipe_resource
*resource
, tmplt
;
120 BOOL has_present_buffers
= FALSE
;
122 unsigned i
, oldBufferCount
, newBufferCount
;
124 DBG("This=%p pParams=%p\n", This
, pParams
);
125 user_assert(pParams
!= NULL
, E_POINTER
);
126 user_assert(pParams
->SwapEffect
, D3DERR_INVALIDCALL
);
127 user_assert((pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
) ||
128 (pParams
->BackBufferCount
<= 1), D3DERR_INVALIDCALL
);
129 user_assert(pDevice
->ex
|| pParams
->BackBufferCount
<= 3, D3DERR_INVALIDCALL
);
130 user_assert(pDevice
->ex
||
131 (pParams
->SwapEffect
== D3DSWAPEFFECT_FLIP
) ||
132 (pParams
->SwapEffect
== D3DSWAPEFFECT_COPY
) ||
133 (pParams
->SwapEffect
== D3DSWAPEFFECT_DISCARD
), D3DERR_INVALIDCALL
);
136 "BackBufferWidth: %u\n"
137 "BackBufferHeight: %u\n"
138 "BackBufferFormat: %s\n"
139 "BackBufferCount: %u\n"
140 "MultiSampleType: %u\n"
141 "MultiSampleQuality: %u\n"
143 "hDeviceWindow: %p\n"
145 "EnableAutoDepthStencil: %i\n"
146 "AutoDepthStencilFormat: %s\n"
148 "FullScreen_RefreshRateInHz: %u\n"
149 "PresentationInterval: %x\n", pParams
,
150 pParams
->BackBufferWidth
, pParams
->BackBufferHeight
,
151 d3dformat_to_string(pParams
->BackBufferFormat
),
152 pParams
->BackBufferCount
,
153 pParams
->MultiSampleType
, pParams
->MultiSampleQuality
,
154 pParams
->SwapEffect
, pParams
->hDeviceWindow
, pParams
->Windowed
,
155 pParams
->EnableAutoDepthStencil
,
156 d3dformat_to_string(pParams
->AutoDepthStencilFormat
),
157 nine_D3DPRESENTFLAG_to_str(pParams
->Flags
),
158 pParams
->FullScreen_RefreshRateInHz
,
159 pParams
->PresentationInterval
);
161 if (pParams
->BackBufferCount
> 3) {
162 pParams
->BackBufferCount
= 3;
165 if (pParams
->BackBufferCount
== 0) {
166 pParams
->BackBufferCount
= 1;
169 if (pParams
->BackBufferFormat
== D3DFMT_UNKNOWN
) {
170 pParams
->BackBufferFormat
= D3DFMT_A8R8G8B8
;
173 This
->desired_fences
= This
->actx
->throttling
? This
->actx
->throttling_value
+ 1 : 0;
174 /* +1 because we add the fence of the current buffer before popping an old one */
175 if (This
->desired_fences
> DRI_SWAP_FENCES_MAX
)
176 This
->desired_fences
= DRI_SWAP_FENCES_MAX
;
178 if (This
->actx
->vblank_mode
== 0)
179 pParams
->PresentationInterval
= D3DPRESENT_INTERVAL_IMMEDIATE
;
180 else if (This
->actx
->vblank_mode
== 3)
181 pParams
->PresentationInterval
= D3DPRESENT_INTERVAL_ONE
;
183 if (mode
&& This
->mode
) {
184 *(This
->mode
) = *mode
;
186 This
->mode
= malloc(sizeof(D3DDISPLAYMODEEX
));
187 memcpy(This
->mode
, mode
, sizeof(D3DDISPLAYMODEEX
));
193 /* Note: It is the role of the backend to fill if necessary
194 * BackBufferWidth and BackBufferHeight */
195 hr
= ID3DPresent_SetPresentParameters(This
->present
, pParams
, This
->mode
);
199 /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
200 * Here we don't get back the initial content of the screen. To emulate the behaviour
201 * we allocate an additional buffer */
202 oldBufferCount
= This
->params
.BackBufferCount
?
203 (This
->params
.BackBufferCount
+
204 (This
->params
.SwapEffect
!= D3DSWAPEFFECT_COPY
)) : 0;
205 newBufferCount
= pParams
->BackBufferCount
+
206 (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
);
208 pf
= d3d9_to_pipe_format_checked(This
->screen
, pParams
->BackBufferFormat
,
209 PIPE_TEXTURE_2D
, pParams
->MultiSampleType
,
210 PIPE_BIND_RENDER_TARGET
, FALSE
, FALSE
);
212 if (This
->actx
->linear_framebuffer
||
213 (pf
!= PIPE_FORMAT_B8G8R8X8_UNORM
&&
214 pf
!= PIPE_FORMAT_B8G8R8A8_UNORM
) ||
215 pParams
->SwapEffect
!= D3DSWAPEFFECT_DISCARD
||
216 pParams
->MultiSampleType
>= 2 ||
217 (This
->actx
->ref
&& This
->actx
->ref
== This
->screen
))
218 has_present_buffers
= TRUE
;
220 /* Note: the buffer depth has to match the window depth.
221 * In practice, ARGB buffers can be used with windows
222 * of depth 24. Windows of depth 32 are extremely rare.
223 * So even if the buffer is ARGB, say it is depth 24.
224 * It is common practice, for example that's how
225 * glamor implements depth 24.
226 * TODO: handle windows with other depths. Not possible in the short term.
227 * For example 16 bits.*/
230 tmplt
.target
= PIPE_TEXTURE_2D
;
231 tmplt
.width0
= pParams
->BackBufferWidth
;
232 tmplt
.height0
= pParams
->BackBufferHeight
;
234 tmplt
.last_level
= 0;
235 tmplt
.array_size
= 1;
236 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
239 desc
.Type
= D3DRTYPE_SURFACE
;
240 desc
.Pool
= D3DPOOL_DEFAULT
;
241 desc
.MultiSampleType
= pParams
->MultiSampleType
;
242 desc
.MultiSampleQuality
= 0;
243 desc
.Width
= pParams
->BackBufferWidth
;
244 desc
.Height
= pParams
->BackBufferHeight
;
247 _mesa_threadpool_destroy(This
, This
->pool
);
250 This
->enable_threadpool
= This
->actx
->thread_submit
&& (pParams
->SwapEffect
!= D3DSWAPEFFECT_COPY
);
251 if (This
->enable_threadpool
)
252 This
->pool
= _mesa_threadpool_create(This
);
254 This
->enable_threadpool
= FALSE
;
256 This
->tasks
= REALLOC(This
->tasks
,
257 oldBufferCount
* sizeof(struct threadpool_task
*),
258 newBufferCount
* sizeof(struct threadpool_task
*));
259 memset(This
->tasks
, 0, newBufferCount
* sizeof(struct threadpool_task
*));
261 for (i
= 0; i
< oldBufferCount
; i
++) {
262 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, This
->present_handles
[i
]);
263 This
->present_handles
[i
] = NULL
;
264 if (This
->present_buffers
)
265 pipe_resource_reference(&(This
->present_buffers
[i
]), NULL
);
268 if (!has_present_buffers
&& This
->present_buffers
) {
269 FREE(This
->present_buffers
);
270 This
->present_buffers
= NULL
;
273 if (newBufferCount
!= oldBufferCount
) {
274 for (i
= newBufferCount
; i
< oldBufferCount
;
276 NineUnknown_Detach(NineUnknown(This
->buffers
[i
]));
278 bufs
= REALLOC(This
->buffers
,
279 oldBufferCount
* sizeof(This
->buffers
[0]),
280 newBufferCount
* sizeof(This
->buffers
[0]));
282 return E_OUTOFMEMORY
;
283 This
->buffers
= bufs
;
284 This
->present_handles
= REALLOC(This
->present_handles
,
285 oldBufferCount
* sizeof(D3DWindowBuffer
*),
286 newBufferCount
* sizeof(D3DWindowBuffer
*));
287 for (i
= oldBufferCount
; i
< newBufferCount
; ++i
) {
288 This
->buffers
[i
] = NULL
;
289 This
->present_handles
[i
] = NULL
;
293 if (has_present_buffers
&&
294 (newBufferCount
!= oldBufferCount
|| !This
->present_buffers
)) {
295 This
->present_buffers
= REALLOC(This
->present_buffers
,
296 This
->present_buffers
== NULL
? 0 :
297 oldBufferCount
* sizeof(struct pipe_resource
*),
298 newBufferCount
* sizeof(struct pipe_resource
*));
299 memset(This
->present_buffers
, 0, newBufferCount
* sizeof(struct pipe_resource
*));
302 for (i
= 0; i
< newBufferCount
; ++i
) {
303 tmplt
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_TRANSFER_READ
|
304 PIPE_BIND_TRANSFER_WRITE
| PIPE_BIND_RENDER_TARGET
;
305 tmplt
.nr_samples
= pParams
->MultiSampleType
;
306 if (!has_present_buffers
)
307 tmplt
.bind
|= PIPE_BIND_SHARED
| PIPE_BIND_SCANOUT
| PIPE_BIND_DISPLAY_TARGET
;
308 tmplt
.format
= d3d9_to_pipe_format_checked(This
->screen
,
309 pParams
->BackBufferFormat
,
312 tmplt
.bind
, FALSE
, FALSE
);
313 if (tmplt
.format
== PIPE_FORMAT_NONE
)
314 return D3DERR_INVALIDCALL
;
315 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
317 DBG("Failed to create pipe_resource.\n");
318 return D3DERR_OUTOFVIDEOMEMORY
;
320 if (pParams
->Flags
& D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
)
321 resource
->flags
|= NINE_RESOURCE_FLAG_LOCKABLE
;
322 if (This
->buffers
[i
]) {
323 NineSurface9_SetResourceResize(This
->buffers
[i
], resource
);
324 if (has_present_buffers
)
325 pipe_resource_reference(&resource
, NULL
);
327 desc
.Format
= pParams
->BackBufferFormat
;
328 desc
.Usage
= D3DUSAGE_RENDERTARGET
;
329 hr
= NineSurface9_new(pDevice
, NineUnknown(This
), resource
, NULL
, 0,
330 0, 0, &desc
, &This
->buffers
[i
]);
331 if (has_present_buffers
)
332 pipe_resource_reference(&resource
, NULL
);
334 DBG("Failed to create RT surface.\n");
337 This
->buffers
[i
]->base
.base
.forward
= FALSE
;
339 if (has_present_buffers
) {
340 tmplt
.format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
341 tmplt
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_SHARED
| PIPE_BIND_SCANOUT
| PIPE_BIND_DISPLAY_TARGET
;
342 tmplt
.nr_samples
= 0;
343 if (This
->actx
->linear_framebuffer
)
344 tmplt
.bind
|= PIPE_BIND_LINEAR
;
345 if (pParams
->SwapEffect
!= D3DSWAPEFFECT_DISCARD
)
346 tmplt
.bind
|= PIPE_BIND_RENDER_TARGET
;
347 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
348 pipe_resource_reference(&(This
->present_buffers
[i
]), resource
);
350 This
->present_handles
[i
] = D3DWindowBuffer_create(This
, resource
, depth
, false);
351 pipe_resource_reference(&resource
, NULL
);
353 if (pParams
->EnableAutoDepthStencil
) {
354 tmplt
.bind
= d3d9_get_pipe_depth_format_bindings(pParams
->AutoDepthStencilFormat
);
355 /* Checking the d3d9 depth format for texture support indicates the app if it can use
356 * the format for shadow mapping or texturing. If the check returns true, then the app
357 * is allowed to use this functionnality, so try first to create the buffer
358 * with PIPE_BIND_SAMPLER_VIEW. If the format can't be created with it, try without.
359 * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support
360 * would fail too, so we are fine. */
361 tmplt
.bind
|= PIPE_BIND_SAMPLER_VIEW
;
362 tmplt
.nr_samples
= pParams
->MultiSampleType
;
363 tmplt
.format
= d3d9_to_pipe_format_checked(This
->screen
,
364 pParams
->AutoDepthStencilFormat
,
369 if (tmplt
.format
== PIPE_FORMAT_NONE
) {
370 tmplt
.bind
&= ~PIPE_BIND_SAMPLER_VIEW
;
371 tmplt
.format
= d3d9_to_pipe_format_checked(This
->screen
,
372 pParams
->AutoDepthStencilFormat
,
379 if (tmplt
.format
== PIPE_FORMAT_NONE
)
380 return D3DERR_INVALIDCALL
;
382 resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
384 DBG("Failed to create pipe_resource for depth buffer.\n");
385 return D3DERR_OUTOFVIDEOMEMORY
;
388 NineSurface9_SetResourceResize(This
->zsbuf
, resource
);
389 pipe_resource_reference(&resource
, NULL
);
391 /* XXX wine thinks the container of this should be the device */
392 desc
.Format
= pParams
->AutoDepthStencilFormat
;
393 desc
.Usage
= D3DUSAGE_DEPTHSTENCIL
;
394 hr
= NineSurface9_new(pDevice
, NineUnknown(pDevice
), resource
, NULL
, 0,
395 0, 0, &desc
, &This
->zsbuf
);
396 pipe_resource_reference(&resource
, NULL
);
398 DBG("Failed to create ZS surface.\n");
401 This
->zsbuf
->base
.base
.forward
= FALSE
;
405 This
->params
= *pParams
;
410 /* Throttling: code adapted from the dri state tracker */
413 * swap_fences_pop_front - pull a fence from the throttle queue
415 * If the throttle queue is filled to the desired number of fences,
416 * pull fences off the queue until the number is less than the desired
417 * number of fences, and return the last fence pulled.
419 static struct pipe_fence_handle
*
420 swap_fences_pop_front(struct NineSwapChain9
*This
)
422 struct pipe_screen
*screen
= This
->screen
;
423 struct pipe_fence_handle
*fence
= NULL
;
425 if (This
->desired_fences
== 0)
428 if (This
->cur_fences
>= This
->desired_fences
) {
429 screen
->fence_reference(screen
, &fence
, This
->swap_fences
[This
->tail
]);
430 screen
->fence_reference(screen
, &This
->swap_fences
[This
->tail
++], NULL
);
431 This
->tail
&= DRI_SWAP_FENCES_MASK
;
439 * swap_fences_see_front - same than swap_fences_pop_front without
444 static struct pipe_fence_handle
*
445 swap_fences_see_front(struct NineSwapChain9
*This
)
447 struct pipe_screen
*screen
= This
->screen
;
448 struct pipe_fence_handle
*fence
= NULL
;
450 if (This
->desired_fences
== 0)
453 if (This
->cur_fences
>= This
->desired_fences
) {
454 screen
->fence_reference(screen
, &fence
, This
->swap_fences
[This
->tail
]);
461 * swap_fences_push_back - push a fence onto the throttle queue at the back
463 * push a fence onto the throttle queue and pull fences of the queue
464 * so that the desired number of fences are on the queue.
467 swap_fences_push_back(struct NineSwapChain9
*This
,
468 struct pipe_fence_handle
*fence
)
470 struct pipe_screen
*screen
= This
->screen
;
472 if (!fence
|| This
->desired_fences
== 0)
475 while(This
->cur_fences
== This
->desired_fences
)
476 swap_fences_pop_front(This
);
479 screen
->fence_reference(screen
, &This
->swap_fences
[This
->head
++],
481 This
->head
&= DRI_SWAP_FENCES_MASK
;
486 * swap_fences_unref - empty the throttle queue
488 * pulls fences of the throttle queue until it is empty.
491 swap_fences_unref(struct NineSwapChain9
*This
)
493 struct pipe_screen
*screen
= This
->screen
;
495 while(This
->cur_fences
) {
496 screen
->fence_reference(screen
, &This
->swap_fences
[This
->tail
++], NULL
);
497 This
->tail
&= DRI_SWAP_FENCES_MASK
;
503 NineSwapChain9_dtor( struct NineSwapChain9
*This
)
507 DBG("This=%p\n", This
);
510 _mesa_threadpool_destroy(This
, This
->pool
);
513 for (i
= 0; i
< This
->params
.BackBufferCount
; i
++) {
514 NineUnknown_Release(NineUnknown(This
->buffers
[i
]));
515 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, This
->present_handles
[i
]);
516 if (This
->present_buffers
)
517 pipe_resource_reference(&(This
->present_buffers
[i
]), NULL
);
520 FREE(This
->present_buffers
);
523 NineUnknown_Destroy(NineUnknown(This
->zsbuf
));
526 ID3DPresent_Release(This
->present
);
528 swap_fences_unref(This
);
529 NineUnknown_dtor(&This
->base
);
533 create_present_buffer( struct NineSwapChain9
*This
,
534 unsigned int width
, unsigned int height
,
535 struct pipe_resource
**resource
,
536 D3DWindowBuffer
**present_handle
)
538 struct pipe_resource tmplt
;
540 tmplt
.target
= PIPE_TEXTURE_2D
;
541 tmplt
.width0
= width
;
542 tmplt
.height0
= height
;
544 tmplt
.last_level
= 0;
545 tmplt
.array_size
= 1;
546 tmplt
.usage
= PIPE_USAGE_DEFAULT
;
548 tmplt
.format
= PIPE_FORMAT_B8G8R8X8_UNORM
;
549 tmplt
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_TRANSFER_READ
|
550 PIPE_BIND_TRANSFER_WRITE
| PIPE_BIND_RENDER_TARGET
|
551 PIPE_BIND_SHARED
| PIPE_BIND_SCANOUT
| PIPE_BIND_DISPLAY_TARGET
;
552 tmplt
.nr_samples
= 0;
553 if (This
->actx
->linear_framebuffer
)
554 tmplt
.bind
|= PIPE_BIND_LINEAR
;
555 *resource
= This
->screen
->resource_create(This
->screen
, &tmplt
);
557 *present_handle
= D3DWindowBuffer_create(This
, *resource
, 24, true);
561 handle_draw_cursor_and_hud( struct NineSwapChain9
*This
, struct pipe_resource
*resource
)
563 struct NineDevice9
*device
= This
->base
.device
;
564 struct pipe_blit_info blit
;
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 This
->pipe
->blit(This
->pipe
, &blit
);
605 if (device
->hud
&& resource
) {
606 hud_draw(device
->hud
, resource
); /* XXX: no offset */
607 /* HUD doesn't clobber stipple */
608 nine_state_restore_non_cso(device
);
612 struct end_present_struct
{
613 struct pipe_screen
*screen
;
614 struct pipe_fence_handle
*fence_to_wait
;
615 ID3DPresent
*present
;
616 D3DWindowBuffer
*present_handle
;
617 HWND hDestWindowOverride
;
620 static void work_present(void *data
)
622 struct end_present_struct
*work
= data
;
623 if (work
->fence_to_wait
) {
624 (void) work
->screen
->fence_finish(work
->screen
, NULL
, work
->fence_to_wait
, PIPE_TIMEOUT_INFINITE
);
625 work
->screen
->fence_reference(work
->screen
, &(work
->fence_to_wait
), NULL
);
627 ID3DPresent_PresentBuffer(work
->present
, work
->present_handle
, work
->hDestWindowOverride
, NULL
, NULL
, NULL
, 0);
631 static void pend_present(struct NineSwapChain9
*This
,
632 HWND hDestWindowOverride
)
634 struct end_present_struct
*work
= calloc(1, sizeof(struct end_present_struct
));
636 work
->screen
= This
->screen
;
637 work
->fence_to_wait
= swap_fences_pop_front(This
);
638 work
->present
= This
->present
;
639 work
->present_handle
= This
->present_handles
[0];
640 work
->hDestWindowOverride
= hDestWindowOverride
;
641 This
->tasks
[0] = _mesa_threadpool_queue_task(This
->pool
, work_present
, work
);
646 static inline HRESULT
647 present( struct NineSwapChain9
*This
,
648 const RECT
*pSourceRect
,
649 const RECT
*pDestRect
,
650 HWND hDestWindowOverride
,
651 const RGNDATA
*pDirtyRegion
,
654 struct pipe_resource
*resource
;
655 struct pipe_fence_handle
*fence
;
657 struct pipe_blit_info blit
;
659 DBG("present: This=%p pSourceRect=%p pDestRect=%p "
660 "pDirtyRegion=%p hDestWindowOverride=%p"
661 "dwFlags=%d resource=%p\n",
662 This
, pSourceRect
, pDestRect
, pDirtyRegion
,
663 hDestWindowOverride
, (int)dwFlags
, This
->buffers
[0]->base
.resource
);
666 DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
667 pSourceRect
->left
, pSourceRect
->right
,
668 pSourceRect
->top
, pSourceRect
->bottom
);
670 DBG("pDestRect = (%u..%u)x(%u..%u)\n",
671 pDestRect
->left
, pDestRect
->right
,
672 pDestRect
->top
, pDestRect
->bottom
);
674 /* TODO: in the case the source and destination rect have different size:
675 * We need to allocate a new buffer, and do a blit to it to resize.
676 * We can't use the present_buffer for that since when we created it,
677 * we couldn't guess which size would have been needed.
678 * If pDestRect or pSourceRect is null, we have to check the sizes
679 * from the source size, and the destination window size.
680 * In this case, either resize rngdata, or pass NULL instead
682 /* Note: This->buffers[0]->level should always be 0 */
684 if (This
->rendering_done
)
685 goto bypass_rendering
;
687 resource
= This
->buffers
[0]->base
.resource
;
689 if (This
->params
.SwapEffect
== D3DSWAPEFFECT_DISCARD
)
690 handle_draw_cursor_and_hud(This
, resource
);
692 if (This
->present_buffers
) {
693 memset(&blit
, 0, sizeof(blit
));
694 blit
.src
.resource
= resource
;
696 blit
.src
.format
= resource
->format
;
698 blit
.src
.box
.depth
= 1;
701 blit
.src
.box
.width
= resource
->width0
;
702 blit
.src
.box
.height
= resource
->height0
;
704 resource
= This
->present_buffers
[0];
706 blit
.dst
.resource
= resource
;
708 blit
.dst
.format
= resource
->format
;
710 blit
.dst
.box
.depth
= 1;
713 blit
.dst
.box
.width
= resource
->width0
;
714 blit
.dst
.box
.height
= resource
->height0
;
716 blit
.mask
= PIPE_MASK_RGBA
;
717 blit
.filter
= PIPE_TEX_FILTER_NEAREST
;
718 blit
.scissor_enable
= FALSE
;
719 blit
.alpha_blend
= FALSE
;
721 This
->pipe
->blit(This
->pipe
, &blit
);
724 /* The resource we present has to resolve fast clears
725 * if needed (and other things) */
726 This
->pipe
->flush_resource(This
->pipe
, resource
);
728 if (This
->params
.SwapEffect
!= D3DSWAPEFFECT_DISCARD
)
729 handle_draw_cursor_and_hud(This
, resource
);
732 This
->pipe
->flush(This
->pipe
, &fence
, PIPE_FLUSH_END_OF_FRAME
);
734 swap_fences_push_back(This
, fence
);
735 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
738 This
->rendering_done
= TRUE
;
741 if (dwFlags
& D3DPRESENT_DONOTWAIT
) {
743 BOOL still_draw
= FALSE
;
744 fence
= swap_fences_see_front(This
);
746 still_draw
= !This
->screen
->fence_finish(This
->screen
, NULL
, fence
, 0);
747 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
750 return D3DERR_WASSTILLDRAWING
;
753 if (!This
->enable_threadpool
) {
755 fence
= swap_fences_pop_front(This
);
757 (void) This
->screen
->fence_finish(This
->screen
, NULL
, fence
, PIPE_TIMEOUT_INFINITE
);
758 This
->screen
->fence_reference(This
->screen
, &fence
, NULL
);
761 hr
= ID3DPresent_PresentBuffer(This
->present
, This
->present_handles
[0], hDestWindowOverride
, pSourceRect
, pDestRect
, pDirtyRegion
, dwFlags
);
763 if (FAILED(hr
)) { UNTESTED(3);return hr
; }
765 pend_present(This
, hDestWindowOverride
);
767 This
->rendering_done
= FALSE
;
773 NineSwapChain9_Present( struct NineSwapChain9
*This
,
774 const RECT
*pSourceRect
,
775 const RECT
*pDestRect
,
776 HWND hDestWindowOverride
,
777 const RGNDATA
*pDirtyRegion
,
780 struct pipe_resource
*res
= NULL
;
781 D3DWindowBuffer
*handle_temp
;
782 struct threadpool_task
*task_temp
;
786 DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
787 "pDirtyRegion=%p dwFlags=%d\n",
788 This
, pSourceRect
, pDestRect
, hDestWindowOverride
,
789 pDirtyRegion
,dwFlags
);
791 if (This
->base
.device
->ex
) {
792 if (NineSwapChain9_GetOccluded(This
)) {
793 return S_PRESENT_OCCLUDED
;
796 if (NineSwapChain9_GetOccluded(This
) ||
797 NineSwapChain9_ResolutionMismatch(This
)) {
798 This
->base
.device
->device_needs_reset
= TRUE
;
800 if (This
->base
.device
->device_needs_reset
) {
801 return D3DERR_DEVICELOST
;
805 hr
= present(This
, pSourceRect
, pDestRect
,
806 hDestWindowOverride
, pDirtyRegion
, dwFlags
);
807 if (hr
== D3DERR_WASSTILLDRAWING
)
810 switch (This
->params
.SwapEffect
) {
811 case D3DSWAPEFFECT_FLIP
:
813 case D3DSWAPEFFECT_DISCARD
:
814 /* rotate the queue */
815 pipe_resource_reference(&res
, This
->buffers
[0]->base
.resource
);
816 for (i
= 1; i
<= This
->params
.BackBufferCount
; i
++) {
817 NineSurface9_SetResourceResize(This
->buffers
[i
- 1],
818 This
->buffers
[i
]->base
.resource
);
820 NineSurface9_SetResourceResize(
821 This
->buffers
[This
->params
.BackBufferCount
], res
);
822 pipe_resource_reference(&res
, NULL
);
824 if (This
->present_buffers
) {
825 pipe_resource_reference(&res
, This
->present_buffers
[0]);
826 for (i
= 1; i
<= This
->params
.BackBufferCount
; i
++)
827 pipe_resource_reference(&(This
->present_buffers
[i
-1]), This
->present_buffers
[i
]);
828 pipe_resource_reference(&(This
->present_buffers
[This
->params
.BackBufferCount
]), res
);
829 pipe_resource_reference(&res
, NULL
);
832 handle_temp
= This
->present_handles
[0];
833 for (i
= 1; i
<= This
->params
.BackBufferCount
; i
++) {
834 This
->present_handles
[i
-1] = This
->present_handles
[i
];
836 This
->present_handles
[This
->params
.BackBufferCount
] = handle_temp
;
837 task_temp
= This
->tasks
[0];
838 for (i
= 1; i
<= This
->params
.BackBufferCount
; i
++) {
839 This
->tasks
[i
-1] = This
->tasks
[i
];
841 This
->tasks
[This
->params
.BackBufferCount
] = task_temp
;
844 case D3DSWAPEFFECT_COPY
:
849 case D3DSWAPEFFECT_OVERLAY
:
850 /* XXX not implemented */
853 case D3DSWAPEFFECT_FLIPEX
:
854 /* XXX not implemented */
859 _mesa_threadpool_wait_for_task(This
->pool
, &(This
->tasks
[0]));
861 ID3DPresent_WaitBufferReleased(This
->present
, This
->present_handles
[0]);
863 This
->base
.device
->state
.changed
.group
|= NINE_STATE_FB
;
869 NineSwapChain9_GetFrontBufferData( struct NineSwapChain9
*This
,
870 IDirect3DSurface9
*pDestSurface
)
872 struct NineSurface9
*dest_surface
= NineSurface9(pDestSurface
);
873 struct NineDevice9
*pDevice
= This
->base
.device
;
874 unsigned int width
, height
;
875 struct pipe_resource
*temp_resource
;
876 struct NineSurface9
*temp_surface
;
877 D3DWindowBuffer
*temp_handle
;
878 D3DSURFACE_DESC desc
;
881 DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
884 user_assert(dest_surface
->base
.pool
== D3DPOOL_SYSTEMMEM
, D3DERR_INVALIDCALL
);
886 width
= dest_surface
->desc
.Width
;
887 height
= dest_surface
->desc
.Height
;
889 /* Note: front window size and destination size are supposed
890 * to match. However it's not very clear what should get taken in Windowed
891 * mode. It may need a fix */
892 create_present_buffer(This
, width
, height
, &temp_resource
, &temp_handle
);
894 desc
.Type
= D3DRTYPE_SURFACE
;
895 desc
.Pool
= D3DPOOL_DEFAULT
;
896 desc
.MultiSampleType
= D3DMULTISAMPLE_NONE
;
897 desc
.MultiSampleQuality
= 0;
899 desc
.Height
= height
;
900 /* NineSurface9_CopyDefaultToMem needs same format. */
901 desc
.Format
= dest_surface
->desc
.Format
;
902 desc
.Usage
= D3DUSAGE_RENDERTARGET
;
903 hr
= NineSurface9_new(pDevice
, NineUnknown(This
), temp_resource
, NULL
, 0,
904 0, 0, &desc
, &temp_surface
);
905 pipe_resource_reference(&temp_resource
, NULL
);
907 DBG("Failed to create temp FrontBuffer surface.\n");
911 ID3DPresent_FrontBufferCopy(This
->present
, temp_handle
);
913 NineSurface9_CopyDefaultToMem(dest_surface
, temp_surface
);
915 ID3DPresent_DestroyD3DWindowBuffer(This
->present
, temp_handle
);
916 NineUnknown_Destroy(NineUnknown(temp_surface
));
922 NineSwapChain9_GetBackBuffer( struct NineSwapChain9
*This
,
924 D3DBACKBUFFER_TYPE Type
,
925 IDirect3DSurface9
**ppBackBuffer
)
927 DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
928 This
, iBackBuffer
, Type
, ppBackBuffer
);
929 (void)user_error(Type
== D3DBACKBUFFER_TYPE_MONO
);
930 /* don't touch ppBackBuffer on error */
931 user_assert(ppBackBuffer
!= NULL
, D3DERR_INVALIDCALL
);
932 user_assert(iBackBuffer
< This
->params
.BackBufferCount
, D3DERR_INVALIDCALL
);
934 NineUnknown_AddRef(NineUnknown(This
->buffers
[iBackBuffer
]));
935 *ppBackBuffer
= (IDirect3DSurface9
*)This
->buffers
[iBackBuffer
];
940 NineSwapChain9_GetRasterStatus( struct NineSwapChain9
*This
,
941 D3DRASTER_STATUS
*pRasterStatus
)
943 DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
944 This
, pRasterStatus
);
945 user_assert(pRasterStatus
!= NULL
, E_POINTER
);
946 return ID3DPresent_GetRasterStatus(This
->present
, pRasterStatus
);
950 NineSwapChain9_GetDisplayMode( struct NineSwapChain9
*This
,
951 D3DDISPLAYMODE
*pMode
)
953 D3DDISPLAYMODEEX mode
;
954 D3DDISPLAYROTATION rot
;
957 DBG("GetDisplayMode: This=%p pMode=%p\n",
959 user_assert(pMode
!= NULL
, E_POINTER
);
961 hr
= ID3DPresent_GetDisplayMode(This
->present
, &mode
, &rot
);
963 pMode
->Width
= mode
.Width
;
964 pMode
->Height
= mode
.Height
;
965 pMode
->RefreshRate
= mode
.RefreshRate
;
966 pMode
->Format
= mode
.Format
;
972 NineSwapChain9_GetPresentParameters( struct NineSwapChain9
*This
,
973 D3DPRESENT_PARAMETERS
*pPresentationParameters
)
975 DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
976 This
, pPresentationParameters
);
977 user_assert(pPresentationParameters
!= NULL
, E_POINTER
);
978 *pPresentationParameters
= This
->params
;
982 IDirect3DSwapChain9Vtbl NineSwapChain9_vtable
= {
983 (void *)NineUnknown_QueryInterface
,
984 (void *)NineUnknown_AddRef
,
985 (void *)NineUnknown_Release
,
986 (void *)NineSwapChain9_Present
,
987 (void *)NineSwapChain9_GetFrontBufferData
,
988 (void *)NineSwapChain9_GetBackBuffer
,
989 (void *)NineSwapChain9_GetRasterStatus
,
990 (void *)NineSwapChain9_GetDisplayMode
,
991 (void *)NineUnknown_GetDevice
, /* actually part of SwapChain9 iface */
992 (void *)NineSwapChain9_GetPresentParameters
995 static const GUID
*NineSwapChain9_IIDs
[] = {
996 &IID_IDirect3DSwapChain9
,
1002 NineSwapChain9_new( struct NineDevice9
*pDevice
,
1004 ID3DPresent
*pPresent
,
1005 D3DPRESENT_PARAMETERS
*pPresentationParameters
,
1006 struct d3dadapter9_context
*pCTX
,
1008 struct NineSwapChain9
**ppOut
)
1010 NINE_DEVICE_CHILD_NEW(SwapChain9
, ppOut
, pDevice
, /* args */
1011 implicit
, pPresent
, pPresentationParameters
,
1012 pCTX
, hFocusWindow
, NULL
);
1016 NineSwapChain9_GetOccluded( struct NineSwapChain9
*This
)
1018 if (This
->base
.device
->minor_version_num
> 0) {
1019 return ID3DPresent_GetWindowOccluded(This
->present
);
1026 NineSwapChain9_ResolutionMismatch( struct NineSwapChain9
*This
)
1028 if (This
->base
.device
->minor_version_num
> 1) {
1029 return ID3DPresent_ResolutionMismatch(This
->present
);
1036 NineSwapChain9_CreateThread( struct NineSwapChain9
*This
,
1040 if (This
->base
.device
->minor_version_num
> 1) {
1041 return ID3DPresent_CreateThread(This
->present
, pFuncAddress
, pParam
);
1048 NineSwapChain9_WaitForThread( struct NineSwapChain9
*This
,
1051 if (This
->base
.device
->minor_version_num
> 1) {
1052 (void) ID3DPresent_WaitForThread(This
->present
, thread
);