c8d3ca158903c87b4b65065583773bb5f3a1f3b0
[mesa.git] / src / gallium / state_trackers / nine / swapchain9.c
1 /*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "swapchain9.h"
24 #include "surface9.h"
25 #include "device9.h"
26
27 #include "nine_helpers.h"
28 #include "nine_pipe.h"
29 #include "nine_dump.h"
30
31 #include "util/u_inlines.h"
32 #include "util/u_surface.h"
33 #include "hud/hud_context.h"
34 #include "state_tracker/drm_driver.h"
35
36 #include "threadpool.h"
37
38 #define DBG_CHANNEL DBG_SWAPCHAIN
39
40 #define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
41
42 HRESULT
43 NineSwapChain9_ctor( struct NineSwapChain9 *This,
44 struct NineUnknownParams *pParams,
45 BOOL implicit,
46 ID3DPresent *pPresent,
47 D3DPRESENT_PARAMETERS *pPresentationParameters,
48 struct d3dadapter9_context *pCTX,
49 HWND hFocusWindow,
50 D3DDISPLAYMODEEX *mode )
51 {
52 HRESULT hr;
53
54 DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
55 This, pParams->device, pPresent, pCTX, hFocusWindow);
56
57 hr = NineUnknown_ctor(&This->base, pParams);
58 if (FAILED(hr))
59 return hr;
60
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;
65 This->actx = pCTX;
66 This->present = pPresent;
67 This->mode = NULL;
68
69 ID3DPresent_AddRef(pPresent);
70
71 if (!pPresentationParameters->hDeviceWindow)
72 pPresentationParameters->hDeviceWindow = hFocusWindow;
73
74 This->rendering_done = FALSE;
75 This->pool = NULL;
76 return NineSwapChain9_Resize(This, pPresentationParameters, mode);
77 }
78
79 static D3DWindowBuffer *
80 D3DWindowBuffer_create(struct NineSwapChain9 *This,
81 struct pipe_resource *resource,
82 int depth)
83 {
84 D3DWindowBuffer *ret;
85 struct winsys_handle whandle;
86 int stride, dmaBufFd;
87
88 memset(&whandle, 0, sizeof(whandle));
89 whandle.type = DRM_API_HANDLE_TYPE_FD;
90 This->screen->resource_get_handle(This->screen, resource, &whandle);
91 stride = whandle.stride;
92 dmaBufFd = whandle.handle;
93 ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
94 dmaBufFd,
95 resource->width0,
96 resource->height0,
97 stride,
98 depth,
99 32,
100 &ret);
101 return ret;
102 }
103
104 HRESULT
105 NineSwapChain9_Resize( struct NineSwapChain9 *This,
106 D3DPRESENT_PARAMETERS *pParams,
107 D3DDISPLAYMODEEX *mode )
108 {
109 struct NineDevice9 *pDevice = This->base.device;
110 struct NineSurface9 **bufs;
111 D3DSURFACE_DESC desc;
112 HRESULT hr;
113 struct pipe_resource *resource, tmplt;
114 enum pipe_format pf;
115 BOOL has_present_buffers = FALSE;
116 int depth;
117 unsigned i, oldBufferCount, newBufferCount;
118
119 DBG("This=%p pParams=%p\n", This, pParams);
120 user_assert(pParams != NULL, E_POINTER);
121 user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL);
122 user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) ||
123 (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL);
124 user_assert(pDevice->ex || pParams->BackBufferCount <= 3, D3DERR_INVALIDCALL);
125 user_assert(pDevice->ex ||
126 (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) ||
127 (pParams->SwapEffect == D3DSWAPEFFECT_COPY) ||
128 (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL);
129
130 DBG("pParams(%p):\n"
131 "BackBufferWidth: %u\n"
132 "BackBufferHeight: %u\n"
133 "BackBufferFormat: %s\n"
134 "BackBufferCount: %u\n"
135 "MultiSampleType: %u\n"
136 "MultiSampleQuality: %u\n"
137 "SwapEffect: %u\n"
138 "hDeviceWindow: %p\n"
139 "Windowed: %i\n"
140 "EnableAutoDepthStencil: %i\n"
141 "AutoDepthStencilFormat: %s\n"
142 "Flags: %s\n"
143 "FullScreen_RefreshRateInHz: %u\n"
144 "PresentationInterval: %x\n", pParams,
145 pParams->BackBufferWidth, pParams->BackBufferHeight,
146 d3dformat_to_string(pParams->BackBufferFormat),
147 pParams->BackBufferCount,
148 pParams->MultiSampleType, pParams->MultiSampleQuality,
149 pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
150 pParams->EnableAutoDepthStencil,
151 d3dformat_to_string(pParams->AutoDepthStencilFormat),
152 nine_D3DPRESENTFLAG_to_str(pParams->Flags),
153 pParams->FullScreen_RefreshRateInHz,
154 pParams->PresentationInterval);
155
156 if (pParams->BackBufferCount > 3) {
157 pParams->BackBufferCount = 3;
158 }
159
160 if (pParams->BackBufferCount == 0) {
161 pParams->BackBufferCount = 1;
162 }
163
164 if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
165 pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
166 }
167
168 This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
169 /* +1 because we add the fence of the current buffer before popping an old one */
170 if (This->desired_fences > DRI_SWAP_FENCES_MAX)
171 This->desired_fences = DRI_SWAP_FENCES_MAX;
172
173 if (This->actx->vblank_mode == 0)
174 pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
175 else if (This->actx->vblank_mode == 3)
176 pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
177
178 if (mode && This->mode) {
179 *(This->mode) = *mode;
180 } else if (mode) {
181 This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
182 memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
183 } else {
184 free(This->mode);
185 This->mode = NULL;
186 }
187
188 /* Note: It is the role of the backend to fill if necessary
189 * BackBufferWidth and BackBufferHeight */
190 hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
191 if (hr != D3D_OK)
192 return hr;
193
194 /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
195 * Here we don't get back the initial content of the screen. To emulate the behaviour
196 * we allocate an additional buffer */
197 oldBufferCount = This->params.BackBufferCount ?
198 (This->params.BackBufferCount +
199 (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0;
200 newBufferCount = pParams->BackBufferCount +
201 (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
202
203 pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat,
204 PIPE_TEXTURE_2D, pParams->MultiSampleType,
205 PIPE_BIND_RENDER_TARGET, FALSE);
206
207 if (This->actx->linear_framebuffer ||
208 (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
209 pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
210 pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
211 pParams->MultiSampleType >= 2 ||
212 (This->actx->ref && This->actx->ref == This->screen))
213 has_present_buffers = TRUE;
214
215 /* Note: the buffer depth has to match the window depth.
216 * In practice, ARGB buffers can be used with windows
217 * of depth 24. Windows of depth 32 are extremely rare.
218 * So even if the buffer is ARGB, say it is depth 24.
219 * It is common practice, for example that's how
220 * glamor implements depth 24.
221 * TODO: handle windows with other depths. Not possible in the short term.
222 * For example 16 bits.*/
223 depth = 24;
224
225 tmplt.target = PIPE_TEXTURE_2D;
226 tmplt.width0 = pParams->BackBufferWidth;
227 tmplt.height0 = pParams->BackBufferHeight;
228 tmplt.depth0 = 1;
229 tmplt.last_level = 0;
230 tmplt.array_size = 1;
231 tmplt.usage = PIPE_USAGE_DEFAULT;
232 tmplt.flags = 0;
233
234 desc.Type = D3DRTYPE_SURFACE;
235 desc.Pool = D3DPOOL_DEFAULT;
236 desc.MultiSampleType = pParams->MultiSampleType;
237 desc.MultiSampleQuality = 0;
238 desc.Width = pParams->BackBufferWidth;
239 desc.Height = pParams->BackBufferHeight;
240
241 if (This->pool) {
242 _mesa_threadpool_destroy(This->pool);
243 This->pool = NULL;
244 }
245 This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
246 if (This->enable_threadpool)
247 This->pool = _mesa_threadpool_create();
248 if (!This->pool)
249 This->enable_threadpool = FALSE;
250
251 This->tasks = REALLOC(This->tasks,
252 oldBufferCount * sizeof(struct threadpool_task *),
253 newBufferCount * sizeof(struct threadpool_task *));
254 memset(This->tasks, 0, newBufferCount * sizeof(struct threadpool_task *));
255
256 for (i = 0; i < oldBufferCount; i++) {
257 ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
258 This->present_handles[i] = NULL;
259 if (This->present_buffers)
260 pipe_resource_reference(&(This->present_buffers[i]), NULL);
261 }
262
263 if (!has_present_buffers && This->present_buffers) {
264 FREE(This->present_buffers);
265 This->present_buffers = NULL;
266 }
267
268 if (newBufferCount != oldBufferCount) {
269 for (i = newBufferCount; i < oldBufferCount;
270 ++i)
271 NineUnknown_Detach(NineUnknown(This->buffers[i]));
272
273 bufs = REALLOC(This->buffers,
274 oldBufferCount * sizeof(This->buffers[0]),
275 newBufferCount * sizeof(This->buffers[0]));
276 if (!bufs)
277 return E_OUTOFMEMORY;
278 This->buffers = bufs;
279 This->present_handles = REALLOC(This->present_handles,
280 oldBufferCount * sizeof(D3DWindowBuffer *),
281 newBufferCount * sizeof(D3DWindowBuffer *));
282 for (i = oldBufferCount; i < newBufferCount; ++i) {
283 This->buffers[i] = NULL;
284 This->present_handles[i] = NULL;
285 }
286 }
287
288 if (has_present_buffers &&
289 (newBufferCount != oldBufferCount || !This->present_buffers)) {
290 This->present_buffers = REALLOC(This->present_buffers,
291 This->present_buffers == NULL ? 0 :
292 oldBufferCount * sizeof(struct pipe_resource *),
293 newBufferCount * sizeof(struct pipe_resource *));
294 memset(This->present_buffers, 0, newBufferCount * sizeof(struct pipe_resource *));
295 }
296
297 for (i = 0; i < newBufferCount; ++i) {
298 tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
299 PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET;
300 tmplt.nr_samples = pParams->MultiSampleType;
301 if (!has_present_buffers)
302 tmplt.bind |= PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
303 tmplt.format = d3d9_to_pipe_format_checked(This->screen,
304 pParams->BackBufferFormat,
305 PIPE_TEXTURE_2D,
306 tmplt.nr_samples,
307 tmplt.bind, FALSE);
308 if (tmplt.format == PIPE_FORMAT_NONE)
309 return D3DERR_INVALIDCALL;
310 resource = This->screen->resource_create(This->screen, &tmplt);
311 if (!resource) {
312 DBG("Failed to create pipe_resource.\n");
313 return D3DERR_OUTOFVIDEOMEMORY;
314 }
315 if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
316 resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
317 if (This->buffers[i]) {
318 NineSurface9_SetResourceResize(This->buffers[i], resource);
319 if (has_present_buffers)
320 pipe_resource_reference(&resource, NULL);
321 } else {
322 desc.Format = pParams->BackBufferFormat;
323 desc.Usage = D3DUSAGE_RENDERTARGET;
324 hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0,
325 0, 0, &desc, &This->buffers[i]);
326 if (has_present_buffers)
327 pipe_resource_reference(&resource, NULL);
328 if (FAILED(hr)) {
329 DBG("Failed to create RT surface.\n");
330 return hr;
331 }
332 This->buffers[i]->base.base.forward = FALSE;
333 }
334 if (has_present_buffers) {
335 tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
336 tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
337 tmplt.nr_samples = 0;
338 if (This->actx->linear_framebuffer)
339 tmplt.bind |= PIPE_BIND_LINEAR;
340 if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
341 tmplt.bind |= PIPE_BIND_RENDER_TARGET;
342 resource = This->screen->resource_create(This->screen, &tmplt);
343 pipe_resource_reference(&(This->present_buffers[i]), resource);
344 }
345 This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth);
346 pipe_resource_reference(&resource, NULL);
347 }
348 if (pParams->EnableAutoDepthStencil) {
349 tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat);
350 /* Checking the d3d9 depth format for texture support indicates the app if it can use
351 * the format for shadow mapping or texturing. If the check returns true, then the app
352 * is allowed to use this functionnality, so try first to create the buffer
353 * with PIPE_BIND_SAMPLER_VIEW. If the format can't be created with it, try without.
354 * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support
355 * would fail too, so we are fine. */
356 tmplt.bind |= PIPE_BIND_SAMPLER_VIEW;
357 tmplt.nr_samples = pParams->MultiSampleType;
358 tmplt.format = d3d9_to_pipe_format_checked(This->screen,
359 pParams->AutoDepthStencilFormat,
360 PIPE_TEXTURE_2D,
361 tmplt.nr_samples,
362 tmplt.bind,
363 FALSE);
364 if (tmplt.format == PIPE_FORMAT_NONE) {
365 tmplt.bind &= ~PIPE_BIND_SAMPLER_VIEW;
366 tmplt.format = d3d9_to_pipe_format_checked(This->screen,
367 pParams->AutoDepthStencilFormat,
368 PIPE_TEXTURE_2D,
369 tmplt.nr_samples,
370 tmplt.bind,
371 FALSE);
372 }
373
374 if (tmplt.format == PIPE_FORMAT_NONE)
375 return D3DERR_INVALIDCALL;
376
377 resource = This->screen->resource_create(This->screen, &tmplt);
378 if (!resource) {
379 DBG("Failed to create pipe_resource for depth buffer.\n");
380 return D3DERR_OUTOFVIDEOMEMORY;
381 }
382 if (This->zsbuf) {
383 NineSurface9_SetResourceResize(This->zsbuf, resource);
384 pipe_resource_reference(&resource, NULL);
385 } else {
386 /* XXX wine thinks the container of this should be the device */
387 desc.Format = pParams->AutoDepthStencilFormat;
388 desc.Usage = D3DUSAGE_DEPTHSTENCIL;
389 hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, NULL, 0,
390 0, 0, &desc, &This->zsbuf);
391 pipe_resource_reference(&resource, NULL);
392 if (FAILED(hr)) {
393 DBG("Failed to create ZS surface.\n");
394 return hr;
395 }
396 This->zsbuf->base.base.forward = FALSE;
397 }
398 }
399
400 This->params = *pParams;
401
402 return D3D_OK;
403 }
404
405 /* Throttling: code adapted from the dri state tracker */
406
407 /**
408 * swap_fences_pop_front - pull a fence from the throttle queue
409 *
410 * If the throttle queue is filled to the desired number of fences,
411 * pull fences off the queue until the number is less than the desired
412 * number of fences, and return the last fence pulled.
413 */
414 static struct pipe_fence_handle *
415 swap_fences_pop_front(struct NineSwapChain9 *This)
416 {
417 struct pipe_screen *screen = This->screen;
418 struct pipe_fence_handle *fence = NULL;
419
420 if (This->desired_fences == 0)
421 return NULL;
422
423 if (This->cur_fences >= This->desired_fences) {
424 screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
425 screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
426 This->tail &= DRI_SWAP_FENCES_MASK;
427 --This->cur_fences;
428 }
429 return fence;
430 }
431
432
433 /**
434 * swap_fences_see_front - same than swap_fences_pop_front without
435 * pulling
436 *
437 */
438
439 static struct pipe_fence_handle *
440 swap_fences_see_front(struct NineSwapChain9 *This)
441 {
442 struct pipe_screen *screen = This->screen;
443 struct pipe_fence_handle *fence = NULL;
444
445 if (This->desired_fences == 0)
446 return NULL;
447
448 if (This->cur_fences >= This->desired_fences) {
449 screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
450 }
451 return fence;
452 }
453
454
455 /**
456 * swap_fences_push_back - push a fence onto the throttle queue at the back
457 *
458 * push a fence onto the throttle queue and pull fences of the queue
459 * so that the desired number of fences are on the queue.
460 */
461 static void
462 swap_fences_push_back(struct NineSwapChain9 *This,
463 struct pipe_fence_handle *fence)
464 {
465 struct pipe_screen *screen = This->screen;
466
467 if (!fence || This->desired_fences == 0)
468 return;
469
470 while(This->cur_fences == This->desired_fences)
471 swap_fences_pop_front(This);
472
473 This->cur_fences++;
474 screen->fence_reference(screen, &This->swap_fences[This->head++],
475 fence);
476 This->head &= DRI_SWAP_FENCES_MASK;
477 }
478
479
480 /**
481 * swap_fences_unref - empty the throttle queue
482 *
483 * pulls fences of the throttle queue until it is empty.
484 */
485 static void
486 swap_fences_unref(struct NineSwapChain9 *This)
487 {
488 struct pipe_screen *screen = This->screen;
489
490 while(This->cur_fences) {
491 screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
492 This->tail &= DRI_SWAP_FENCES_MASK;
493 --This->cur_fences;
494 }
495 }
496
497 void
498 NineSwapChain9_dtor( struct NineSwapChain9 *This )
499 {
500 unsigned i;
501
502 DBG("This=%p\n", This);
503
504 if (This->pool)
505 _mesa_threadpool_destroy(This->pool);
506
507 if (This->buffers) {
508 for (i = 0; i < This->params.BackBufferCount; i++) {
509 NineUnknown_Release(NineUnknown(This->buffers[i]));
510 ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
511 if (This->present_buffers)
512 pipe_resource_reference(&(This->present_buffers[i]), NULL);
513 }
514 FREE(This->buffers);
515 FREE(This->present_buffers);
516 }
517 if (This->zsbuf)
518 NineUnknown_Destroy(NineUnknown(This->zsbuf));
519
520 if (This->present)
521 ID3DPresent_Release(This->present);
522
523 swap_fences_unref(This);
524 NineUnknown_dtor(&This->base);
525 }
526
527 static void
528 create_present_buffer( struct NineSwapChain9 *This,
529 unsigned int width, unsigned int height,
530 struct pipe_resource **resource,
531 D3DWindowBuffer **present_handle)
532 {
533 struct pipe_resource tmplt;
534
535 tmplt.target = PIPE_TEXTURE_2D;
536 tmplt.width0 = width;
537 tmplt.height0 = height;
538 tmplt.depth0 = 1;
539 tmplt.last_level = 0;
540 tmplt.array_size = 1;
541 tmplt.usage = PIPE_USAGE_DEFAULT;
542 tmplt.flags = 0;
543 tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
544 tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
545 PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET |
546 PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
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);
551
552 *present_handle = D3DWindowBuffer_create(This, *resource, 24);
553 }
554
555 static void
556 handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
557 {
558 struct NineDevice9 *device = This->base.device;
559 struct pipe_blit_info blit;
560
561 if (device->cursor.software && device->cursor.visible && device->cursor.w) {
562 memset(&blit, 0, sizeof(blit));
563 blit.src.resource = device->cursor.image;
564 blit.src.level = 0;
565 blit.src.format = device->cursor.image->format;
566 blit.src.box.x = 0;
567 blit.src.box.y = 0;
568 blit.src.box.z = 0;
569 blit.src.box.depth = 1;
570 blit.src.box.width = device->cursor.w;
571 blit.src.box.height = device->cursor.h;
572
573 blit.dst.resource = resource;
574 blit.dst.level = 0;
575 blit.dst.format = resource->format;
576 blit.dst.box.z = 0;
577 blit.dst.box.depth = 1;
578
579 blit.mask = PIPE_MASK_RGBA;
580 blit.filter = PIPE_TEX_FILTER_NEAREST;
581 blit.scissor_enable = FALSE;
582
583 /* NOTE: blit messes up when box.x + box.width < 0, fix driver
584 * NOTE2: device->cursor.pos contains coordinates relative to the screen.
585 * This happens to be also the position of the cursor when we are fullscreen.
586 * We don't use sw cursor for Windowed mode */
587 blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
588 blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
589 blit.dst.box.width = blit.src.box.width;
590 blit.dst.box.height = blit.src.box.height;
591
592 DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
593 blit.src.box.width, blit.src.box.height,
594 blit.dst.box.x, blit.dst.box.y);
595
596 blit.alpha_blend = TRUE;
597 This->pipe->blit(This->pipe, &blit);
598 }
599
600 if (device->hud && resource) {
601 hud_draw(device->hud, resource); /* XXX: no offset */
602 /* HUD doesn't clobber stipple */
603 nine_state_restore_non_cso(device);
604 }
605 }
606
607 struct end_present_struct {
608 struct pipe_screen *screen;
609 struct pipe_fence_handle *fence_to_wait;
610 ID3DPresent *present;
611 D3DWindowBuffer *present_handle;
612 HWND hDestWindowOverride;
613 };
614
615 static void work_present(void *data)
616 {
617 struct end_present_struct *work = data;
618 if (work->fence_to_wait) {
619 (void) work->screen->fence_finish(work->screen, work->fence_to_wait, PIPE_TIMEOUT_INFINITE);
620 work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL);
621 }
622 ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0);
623 free(work);
624 }
625
626 static void pend_present(struct NineSwapChain9 *This,
627 HWND hDestWindowOverride)
628 {
629 struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct));
630
631 work->screen = This->screen;
632 work->fence_to_wait = swap_fences_pop_front(This);
633 work->present = This->present;
634 work->present_handle = This->present_handles[0];
635 work->hDestWindowOverride = hDestWindowOverride;
636 This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work);
637
638 return;
639 }
640
641 static inline HRESULT
642 present( struct NineSwapChain9 *This,
643 const RECT *pSourceRect,
644 const RECT *pDestRect,
645 HWND hDestWindowOverride,
646 const RGNDATA *pDirtyRegion,
647 DWORD dwFlags )
648 {
649 struct pipe_resource *resource;
650 struct pipe_fence_handle *fence;
651 HRESULT hr;
652 struct pipe_blit_info blit;
653
654 DBG("present: This=%p pSourceRect=%p pDestRect=%p "
655 "pDirtyRegion=%p hDestWindowOverride=%p"
656 "dwFlags=%d resource=%p\n",
657 This, pSourceRect, pDestRect, pDirtyRegion,
658 hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
659
660 if (pSourceRect)
661 DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
662 pSourceRect->left, pSourceRect->right,
663 pSourceRect->top, pSourceRect->bottom);
664 if (pDestRect)
665 DBG("pDestRect = (%u..%u)x(%u..%u)\n",
666 pDestRect->left, pDestRect->right,
667 pDestRect->top, pDestRect->bottom);
668
669 /* TODO: in the case the source and destination rect have different size:
670 * We need to allocate a new buffer, and do a blit to it to resize.
671 * We can't use the present_buffer for that since when we created it,
672 * we couldn't guess which size would have been needed.
673 * If pDestRect or pSourceRect is null, we have to check the sizes
674 * from the source size, and the destination window size.
675 * In this case, either resize rngdata, or pass NULL instead
676 */
677 /* Note: This->buffers[0]->level should always be 0 */
678
679 if (This->rendering_done)
680 goto bypass_rendering;
681
682 resource = This->buffers[0]->base.resource;
683
684 if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
685 handle_draw_cursor_and_hud(This, resource);
686
687 if (This->present_buffers) {
688 memset(&blit, 0, sizeof(blit));
689 blit.src.resource = resource;
690 blit.src.level = 0;
691 blit.src.format = resource->format;
692 blit.src.box.z = 0;
693 blit.src.box.depth = 1;
694 blit.src.box.x = 0;
695 blit.src.box.y = 0;
696 blit.src.box.width = resource->width0;
697 blit.src.box.height = resource->height0;
698
699 resource = This->present_buffers[0];
700
701 blit.dst.resource = resource;
702 blit.dst.level = 0;
703 blit.dst.format = resource->format;
704 blit.dst.box.z = 0;
705 blit.dst.box.depth = 1;
706 blit.dst.box.x = 0;
707 blit.dst.box.y = 0;
708 blit.dst.box.width = resource->width0;
709 blit.dst.box.height = resource->height0;
710
711 blit.mask = PIPE_MASK_RGBA;
712 blit.filter = PIPE_TEX_FILTER_NEAREST;
713 blit.scissor_enable = FALSE;
714 blit.alpha_blend = FALSE;
715
716 This->pipe->blit(This->pipe, &blit);
717 }
718
719 /* The resource we present has to resolve fast clears
720 * if needed (and other things) */
721 This->pipe->flush_resource(This->pipe, resource);
722
723 if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
724 handle_draw_cursor_and_hud(This, resource);
725
726 fence = NULL;
727 This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
728 if (fence) {
729 swap_fences_push_back(This, fence);
730 This->screen->fence_reference(This->screen, &fence, NULL);
731 }
732
733 This->rendering_done = TRUE;
734 bypass_rendering:
735
736 if (dwFlags & D3DPRESENT_DONOTWAIT) {
737 UNTESTED(2);
738 BOOL still_draw = FALSE;
739 fence = swap_fences_see_front(This);
740 if (fence) {
741 still_draw = !This->screen->fence_finish(This->screen, fence, 0);
742 This->screen->fence_reference(This->screen, &fence, NULL);
743 }
744 if (still_draw)
745 return D3DERR_WASSTILLDRAWING;
746 }
747
748 if (!This->enable_threadpool) {
749 This->tasks[0]=NULL;
750 fence = swap_fences_pop_front(This);
751 if (fence) {
752 (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE);
753 This->screen->fence_reference(This->screen, &fence, NULL);
754 }
755
756 hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags);
757
758 if (FAILED(hr)) { UNTESTED(3);return hr; }
759 } else {
760 pend_present(This, hDestWindowOverride);
761 }
762 This->rendering_done = FALSE;
763
764 return D3D_OK;
765 }
766
767 HRESULT WINAPI
768 NineSwapChain9_Present( struct NineSwapChain9 *This,
769 const RECT *pSourceRect,
770 const RECT *pDestRect,
771 HWND hDestWindowOverride,
772 const RGNDATA *pDirtyRegion,
773 DWORD dwFlags )
774 {
775 struct pipe_resource *res = NULL;
776 D3DWindowBuffer *handle_temp;
777 struct threadpool_task *task_temp;
778 int i;
779 HRESULT hr = present(This, pSourceRect, pDestRect,
780 hDestWindowOverride, pDirtyRegion, dwFlags);
781
782 DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
783 "pDirtyRegion=%p dwFlags=%d\n",
784 This, pSourceRect, pDestRect, hDestWindowOverride,
785 pDirtyRegion,dwFlags);
786
787 if (hr == D3DERR_WASSTILLDRAWING)
788 return hr;
789
790 switch (This->params.SwapEffect) {
791 case D3DSWAPEFFECT_FLIP:
792 UNTESTED(4);
793 case D3DSWAPEFFECT_DISCARD:
794 /* rotate the queue */
795 pipe_resource_reference(&res, This->buffers[0]->base.resource);
796 for (i = 1; i <= This->params.BackBufferCount; i++) {
797 NineSurface9_SetResourceResize(This->buffers[i - 1],
798 This->buffers[i]->base.resource);
799 }
800 NineSurface9_SetResourceResize(
801 This->buffers[This->params.BackBufferCount], res);
802 pipe_resource_reference(&res, NULL);
803
804 if (This->present_buffers) {
805 pipe_resource_reference(&res, This->present_buffers[0]);
806 for (i = 1; i <= This->params.BackBufferCount; i++)
807 pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
808 pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res);
809 pipe_resource_reference(&res, NULL);
810 }
811
812 handle_temp = This->present_handles[0];
813 for (i = 1; i <= This->params.BackBufferCount; i++) {
814 This->present_handles[i-1] = This->present_handles[i];
815 }
816 This->present_handles[This->params.BackBufferCount] = handle_temp;
817 task_temp = This->tasks[0];
818 for (i = 1; i <= This->params.BackBufferCount; i++) {
819 This->tasks[i-1] = This->tasks[i];
820 }
821 This->tasks[This->params.BackBufferCount] = task_temp;
822 break;
823
824 case D3DSWAPEFFECT_COPY:
825 UNTESTED(5);
826 /* do nothing */
827 break;
828
829 case D3DSWAPEFFECT_OVERLAY:
830 /* XXX not implemented */
831 break;
832
833 case D3DSWAPEFFECT_FLIPEX:
834 /* XXX not implemented */
835 break;
836 }
837
838 if (This->tasks[0])
839 _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
840
841 ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
842
843 This->base.device->state.changed.group |= NINE_STATE_FB;
844 nine_update_state_framebuffer(This->base.device);
845
846 return hr;
847 }
848
849 HRESULT WINAPI
850 NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
851 IDirect3DSurface9 *pDestSurface )
852 {
853 struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
854 struct NineDevice9 *pDevice = This->base.device;
855 unsigned int width, height;
856 struct pipe_resource *temp_resource;
857 struct NineSurface9 *temp_surface;
858 D3DWindowBuffer *temp_handle;
859 D3DSURFACE_DESC desc;
860 HRESULT hr;
861
862 DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
863 This, pDestSurface);
864
865 user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
866
867 width = dest_surface->desc.Width;
868 height = dest_surface->desc.Height;
869
870 /* Note: front window size and destination size are supposed
871 * to match. However it's not very clear what should get taken in Windowed
872 * mode. It may need a fix */
873 create_present_buffer(This, width, height, &temp_resource, &temp_handle);
874
875 desc.Type = D3DRTYPE_SURFACE;
876 desc.Pool = D3DPOOL_DEFAULT;
877 desc.MultiSampleType = D3DMULTISAMPLE_NONE;
878 desc.MultiSampleQuality = 0;
879 desc.Width = width;
880 desc.Height = height;
881 /* NineSurface9_CopyDefaultToMem needs same format. */
882 desc.Format = dest_surface->desc.Format;
883 desc.Usage = D3DUSAGE_RENDERTARGET;
884 hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0,
885 0, 0, &desc, &temp_surface);
886 pipe_resource_reference(&temp_resource, NULL);
887 if (FAILED(hr)) {
888 DBG("Failed to create temp FrontBuffer surface.\n");
889 return hr;
890 }
891
892 ID3DPresent_FrontBufferCopy(This->present, temp_handle);
893
894 NineSurface9_CopyDefaultToMem(dest_surface, temp_surface);
895
896 ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
897 NineUnknown_Destroy(NineUnknown(temp_surface));
898
899 return D3D_OK;
900 }
901
902 HRESULT WINAPI
903 NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
904 UINT iBackBuffer,
905 D3DBACKBUFFER_TYPE Type,
906 IDirect3DSurface9 **ppBackBuffer )
907 {
908 DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
909 This, iBackBuffer, Type, ppBackBuffer);
910 (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
911 /* don't touch ppBackBuffer on error */
912 user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
913 user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
914
915 NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
916 *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
917 return D3D_OK;
918 }
919
920 HRESULT WINAPI
921 NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
922 D3DRASTER_STATUS *pRasterStatus )
923 {
924 DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
925 This, pRasterStatus);
926 user_assert(pRasterStatus != NULL, E_POINTER);
927 return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
928 }
929
930 HRESULT WINAPI
931 NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
932 D3DDISPLAYMODE *pMode )
933 {
934 D3DDISPLAYMODEEX mode;
935 D3DDISPLAYROTATION rot;
936 HRESULT hr;
937
938 DBG("GetDisplayMode: This=%p pMode=%p\n",
939 This, pMode);
940 user_assert(pMode != NULL, E_POINTER);
941
942 hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
943 if (SUCCEEDED(hr)) {
944 pMode->Width = mode.Width;
945 pMode->Height = mode.Height;
946 pMode->RefreshRate = mode.RefreshRate;
947 pMode->Format = mode.Format;
948 }
949 return hr;
950 }
951
952 HRESULT WINAPI
953 NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
954 D3DPRESENT_PARAMETERS *pPresentationParameters )
955 {
956 DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
957 This, pPresentationParameters);
958 user_assert(pPresentationParameters != NULL, E_POINTER);
959 *pPresentationParameters = This->params;
960 return D3D_OK;
961 }
962
963 IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
964 (void *)NineUnknown_QueryInterface,
965 (void *)NineUnknown_AddRef,
966 (void *)NineUnknown_Release,
967 (void *)NineSwapChain9_Present,
968 (void *)NineSwapChain9_GetFrontBufferData,
969 (void *)NineSwapChain9_GetBackBuffer,
970 (void *)NineSwapChain9_GetRasterStatus,
971 (void *)NineSwapChain9_GetDisplayMode,
972 (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
973 (void *)NineSwapChain9_GetPresentParameters
974 };
975
976 static const GUID *NineSwapChain9_IIDs[] = {
977 &IID_IDirect3DSwapChain9,
978 &IID_IUnknown,
979 NULL
980 };
981
982 HRESULT
983 NineSwapChain9_new( struct NineDevice9 *pDevice,
984 BOOL implicit,
985 ID3DPresent *pPresent,
986 D3DPRESENT_PARAMETERS *pPresentationParameters,
987 struct d3dadapter9_context *pCTX,
988 HWND hFocusWindow,
989 struct NineSwapChain9 **ppOut )
990 {
991 NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
992 implicit, pPresent, pPresentationParameters,
993 pCTX, hFocusWindow, NULL);
994 }