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