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