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