Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Copyright 2011 Joakim Sindholt |
||
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 | 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 | pipe_resource_reference(&resource, NULL); |
||
342 | } |
||
343 | if (pParams->EnableAutoDepthStencil) { |
||
344 | tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat); |
||
345 | /* Checking the d3d9 depth format for texture support indicates the app if it can use |
||
346 | * the format for shadow mapping or texturing. If the check returns true, then the app |
||
347 | * is allowed to use this functionnality, so try first to create the buffer |
||
348 | * with PIPE_BIND_SAMPLER_VIEW. If the format can't be created with it, try without. |
||
349 | * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support |
||
350 | * would fail too, so we are fine. */ |
||
351 | tmplt.bind |= PIPE_BIND_SAMPLER_VIEW; |
||
352 | tmplt.nr_samples = pParams->MultiSampleType; |
||
353 | tmplt.format = d3d9_to_pipe_format_checked(This->screen, |
||
354 | pParams->AutoDepthStencilFormat, |
||
355 | PIPE_TEXTURE_2D, |
||
356 | tmplt.nr_samples, |
||
357 | tmplt.bind, |
||
358 | FALSE); |
||
359 | if (tmplt.format == PIPE_FORMAT_NONE) { |
||
360 | tmplt.bind &= ~PIPE_BIND_SAMPLER_VIEW; |
||
361 | tmplt.format = d3d9_to_pipe_format_checked(This->screen, |
||
362 | pParams->AutoDepthStencilFormat, |
||
363 | PIPE_TEXTURE_2D, |
||
364 | tmplt.nr_samples, |
||
365 | tmplt.bind, |
||
366 | FALSE); |
||
367 | } |
||
368 | |||
369 | if (tmplt.format == PIPE_FORMAT_NONE) |
||
370 | return D3DERR_INVALIDCALL; |
||
371 | |||
372 | resource = This->screen->resource_create(This->screen, &tmplt); |
||
373 | if (!resource) { |
||
374 | DBG("Failed to create pipe_resource for depth buffer.\n"); |
||
375 | return D3DERR_OUTOFVIDEOMEMORY; |
||
376 | } |
||
377 | if (This->zsbuf) { |
||
378 | NineSurface9_SetResourceResize(This->zsbuf, resource); |
||
379 | pipe_resource_reference(&resource, NULL); |
||
380 | } else { |
||
381 | /* XXX wine thinks the container of this should be the device */ |
||
382 | desc.Format = pParams->AutoDepthStencilFormat; |
||
383 | desc.Usage = D3DUSAGE_DEPTHSTENCIL; |
||
384 | hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, NULL, 0, |
||
385 | 0, 0, &desc, &This->zsbuf); |
||
386 | pipe_resource_reference(&resource, NULL); |
||
387 | if (FAILED(hr)) { |
||
388 | DBG("Failed to create ZS surface.\n"); |
||
389 | return hr; |
||
390 | } |
||
391 | This->zsbuf->base.base.forward = FALSE; |
||
392 | } |
||
393 | } |
||
394 | |||
395 | This->params = *pParams; |
||
396 | |||
397 | return D3D_OK; |
||
398 | } |
||
399 | |||
400 | /* Throttling: code adapted from the dri state tracker */ |
||
401 | |||
402 | /** |
||
403 | * swap_fences_pop_front - pull a fence from the throttle queue |
||
404 | * |
||
405 | * If the throttle queue is filled to the desired number of fences, |
||
406 | * pull fences off the queue until the number is less than the desired |
||
407 | * number of fences, and return the last fence pulled. |
||
408 | */ |
||
409 | static struct pipe_fence_handle * |
||
410 | swap_fences_pop_front(struct NineSwapChain9 *This) |
||
411 | { |
||
412 | struct pipe_screen *screen = This->screen; |
||
413 | struct pipe_fence_handle *fence = NULL; |
||
414 | |||
415 | if (This->desired_fences == 0) |
||
416 | return NULL; |
||
417 | |||
418 | if (This->cur_fences >= This->desired_fences) { |
||
419 | screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); |
||
420 | screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); |
||
421 | This->tail &= DRI_SWAP_FENCES_MASK; |
||
422 | --This->cur_fences; |
||
423 | } |
||
424 | return fence; |
||
425 | } |
||
426 | |||
427 | |||
428 | /** |
||
429 | * swap_fences_see_front - same than swap_fences_pop_front without |
||
430 | * pulling |
||
431 | * |
||
432 | */ |
||
433 | |||
434 | static struct pipe_fence_handle * |
||
435 | swap_fences_see_front(struct NineSwapChain9 *This) |
||
436 | { |
||
437 | struct pipe_screen *screen = This->screen; |
||
438 | struct pipe_fence_handle *fence = NULL; |
||
439 | |||
440 | if (This->desired_fences == 0) |
||
441 | return NULL; |
||
442 | |||
443 | if (This->cur_fences >= This->desired_fences) { |
||
444 | screen->fence_reference(screen, &fence, This->swap_fences[This->tail]); |
||
445 | } |
||
446 | return fence; |
||
447 | } |
||
448 | |||
449 | |||
450 | /** |
||
451 | * swap_fences_push_back - push a fence onto the throttle queue at the back |
||
452 | * |
||
453 | * push a fence onto the throttle queue and pull fences of the queue |
||
454 | * so that the desired number of fences are on the queue. |
||
455 | */ |
||
456 | static void |
||
457 | swap_fences_push_back(struct NineSwapChain9 *This, |
||
458 | struct pipe_fence_handle *fence) |
||
459 | { |
||
460 | struct pipe_screen *screen = This->screen; |
||
461 | |||
462 | if (!fence || This->desired_fences == 0) |
||
463 | return; |
||
464 | |||
465 | while(This->cur_fences == This->desired_fences) |
||
466 | swap_fences_pop_front(This); |
||
467 | |||
468 | This->cur_fences++; |
||
469 | screen->fence_reference(screen, &This->swap_fences[This->head++], |
||
470 | fence); |
||
471 | This->head &= DRI_SWAP_FENCES_MASK; |
||
472 | } |
||
473 | |||
474 | |||
475 | /** |
||
476 | * swap_fences_unref - empty the throttle queue |
||
477 | * |
||
478 | * pulls fences of the throttle queue until it is empty. |
||
479 | */ |
||
480 | static void |
||
481 | swap_fences_unref(struct NineSwapChain9 *This) |
||
482 | { |
||
483 | struct pipe_screen *screen = This->screen; |
||
484 | |||
485 | while(This->cur_fences) { |
||
486 | screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL); |
||
487 | This->tail &= DRI_SWAP_FENCES_MASK; |
||
488 | --This->cur_fences; |
||
489 | } |
||
490 | } |
||
491 | |||
492 | void |
||
493 | NineSwapChain9_dtor( struct NineSwapChain9 *This ) |
||
494 | { |
||
495 | unsigned i; |
||
496 | |||
497 | DBG("This=%p\n", This); |
||
498 | |||
499 | if (This->pool) |
||
500 | _mesa_threadpool_destroy(This->pool); |
||
501 | |||
502 | if (This->buffers) { |
||
503 | for (i = 0; i < This->params.BackBufferCount; i++) { |
||
504 | NineUnknown_Release(NineUnknown(This->buffers[i])); |
||
505 | ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); |
||
506 | if (This->present_buffers) |
||
507 | pipe_resource_reference(&(This->present_buffers[i]), NULL); |
||
508 | } |
||
509 | FREE(This->buffers); |
||
510 | FREE(This->present_buffers); |
||
511 | } |
||
512 | if (This->zsbuf) |
||
513 | NineUnknown_Destroy(NineUnknown(This->zsbuf)); |
||
514 | |||
515 | if (This->present) |
||
516 | ID3DPresent_Release(This->present); |
||
517 | |||
518 | swap_fences_unref(This); |
||
519 | NineUnknown_dtor(&This->base); |
||
520 | } |
||
521 | |||
522 | static void |
||
523 | create_present_buffer( struct NineSwapChain9 *This, |
||
524 | unsigned int width, unsigned int height, |
||
525 | struct pipe_resource **resource, |
||
526 | D3DWindowBuffer **present_handle) |
||
527 | { |
||
528 | struct pipe_resource tmplt; |
||
529 | |||
530 | tmplt.target = PIPE_TEXTURE_2D; |
||
531 | tmplt.width0 = width; |
||
532 | tmplt.height0 = height; |
||
533 | tmplt.depth0 = 1; |
||
534 | tmplt.last_level = 0; |
||
535 | tmplt.array_size = 1; |
||
536 | tmplt.usage = PIPE_USAGE_DEFAULT; |
||
537 | tmplt.flags = 0; |
||
538 | tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM; |
||
539 | tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ | |
||
540 | PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET | |
||
541 | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET; |
||
542 | tmplt.nr_samples = 0; |
||
543 | if (This->actx->linear_framebuffer) |
||
544 | tmplt.bind |= PIPE_BIND_LINEAR; |
||
545 | *resource = This->screen->resource_create(This->screen, &tmplt); |
||
546 | |||
547 | *present_handle = D3DWindowBuffer_create(This, *resource, 24); |
||
548 | } |
||
549 | |||
550 | static void |
||
551 | handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource) |
||
552 | { |
||
553 | struct NineDevice9 *device = This->base.device; |
||
554 | struct pipe_blit_info blit; |
||
555 | |||
556 | if (device->cursor.software && device->cursor.visible && device->cursor.w) { |
||
557 | memset(&blit, 0, sizeof(blit)); |
||
558 | blit.src.resource = device->cursor.image; |
||
559 | blit.src.level = 0; |
||
560 | blit.src.format = device->cursor.image->format; |
||
561 | blit.src.box.x = 0; |
||
562 | blit.src.box.y = 0; |
||
563 | blit.src.box.z = 0; |
||
564 | blit.src.box.depth = 1; |
||
565 | blit.src.box.width = device->cursor.w; |
||
566 | blit.src.box.height = device->cursor.h; |
||
567 | |||
568 | blit.dst.resource = resource; |
||
569 | blit.dst.level = 0; |
||
570 | blit.dst.format = resource->format; |
||
571 | blit.dst.box.z = 0; |
||
572 | blit.dst.box.depth = 1; |
||
573 | |||
574 | blit.mask = PIPE_MASK_RGBA; |
||
575 | blit.filter = PIPE_TEX_FILTER_NEAREST; |
||
576 | blit.scissor_enable = FALSE; |
||
577 | |||
578 | ID3DPresent_GetCursorPos(This->present, &device->cursor.pos); |
||
579 | |||
580 | /* NOTE: blit messes up when box.x + box.width < 0, fix driver */ |
||
581 | blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x; |
||
582 | blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y; |
||
583 | blit.dst.box.width = blit.src.box.width; |
||
584 | blit.dst.box.height = blit.src.box.height; |
||
585 | |||
586 | DBG("Blitting cursor(%ux%u) to (%i,%i).\n", |
||
587 | blit.src.box.width, blit.src.box.height, |
||
588 | blit.dst.box.x, blit.dst.box.y); |
||
589 | |||
590 | This->pipe->blit(This->pipe, &blit); |
||
591 | } |
||
592 | |||
593 | if (device->hud && resource) { |
||
594 | hud_draw(device->hud, resource); /* XXX: no offset */ |
||
595 | /* HUD doesn't clobber stipple */ |
||
596 | NineDevice9_RestoreNonCSOState(device, ~0x2); |
||
597 | } |
||
598 | } |
||
599 | |||
600 | struct end_present_struct { |
||
601 | struct pipe_screen *screen; |
||
602 | struct pipe_fence_handle *fence_to_wait; |
||
603 | ID3DPresent *present; |
||
604 | D3DWindowBuffer *present_handle; |
||
605 | HWND hDestWindowOverride; |
||
606 | }; |
||
607 | |||
608 | static void work_present(void *data) |
||
609 | { |
||
610 | struct end_present_struct *work = data; |
||
611 | if (work->fence_to_wait) { |
||
612 | (void) work->screen->fence_finish(work->screen, work->fence_to_wait, PIPE_TIMEOUT_INFINITE); |
||
613 | work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL); |
||
614 | } |
||
615 | ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0); |
||
616 | free(work); |
||
617 | } |
||
618 | |||
619 | static void pend_present(struct NineSwapChain9 *This, |
||
620 | HWND hDestWindowOverride) |
||
621 | { |
||
622 | struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct)); |
||
623 | |||
624 | work->screen = This->screen; |
||
625 | work->fence_to_wait = swap_fences_pop_front(This); |
||
626 | work->present = This->present; |
||
627 | work->present_handle = This->present_handles[0]; |
||
628 | work->hDestWindowOverride = hDestWindowOverride; |
||
629 | This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work); |
||
630 | |||
631 | return; |
||
632 | } |
||
633 | |||
634 | static INLINE HRESULT |
||
635 | present( struct NineSwapChain9 *This, |
||
636 | const RECT *pSourceRect, |
||
637 | const RECT *pDestRect, |
||
638 | HWND hDestWindowOverride, |
||
639 | const RGNDATA *pDirtyRegion, |
||
640 | DWORD dwFlags ) |
||
641 | { |
||
642 | struct pipe_resource *resource; |
||
643 | struct pipe_fence_handle *fence; |
||
644 | HRESULT hr; |
||
645 | struct pipe_blit_info blit; |
||
646 | |||
647 | DBG("present: This=%p pSourceRect=%p pDestRect=%p " |
||
648 | "pDirtyRegion=%p hDestWindowOverride=%p" |
||
649 | "dwFlags=%d resource=%p\n", |
||
650 | This, pSourceRect, pDestRect, pDirtyRegion, |
||
651 | hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource); |
||
652 | |||
653 | if (pSourceRect) |
||
654 | DBG("pSourceRect = (%u..%u)x(%u..%u)\n", |
||
655 | pSourceRect->left, pSourceRect->right, |
||
656 | pSourceRect->top, pSourceRect->bottom); |
||
657 | if (pDestRect) |
||
658 | DBG("pDestRect = (%u..%u)x(%u..%u)\n", |
||
659 | pDestRect->left, pDestRect->right, |
||
660 | pDestRect->top, pDestRect->bottom); |
||
661 | |||
662 | /* TODO: in the case the source and destination rect have different size: |
||
663 | * We need to allocate a new buffer, and do a blit to it to resize. |
||
664 | * We can't use the present_buffer for that since when we created it, |
||
665 | * we couldn't guess which size would have been needed. |
||
666 | * If pDestRect or pSourceRect is null, we have to check the sizes |
||
667 | * from the source size, and the destination window size. |
||
668 | * In this case, either resize rngdata, or pass NULL instead |
||
669 | */ |
||
670 | /* Note: This->buffers[0]->level should always be 0 */ |
||
671 | |||
672 | if (This->rendering_done) |
||
673 | goto bypass_rendering; |
||
674 | |||
675 | resource = This->buffers[0]->base.resource; |
||
676 | |||
677 | if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD) |
||
678 | handle_draw_cursor_and_hud(This, resource); |
||
679 | |||
680 | if (This->present_buffers) { |
||
681 | memset(&blit, 0, sizeof(blit)); |
||
682 | blit.src.resource = resource; |
||
683 | blit.src.level = 0; |
||
684 | blit.src.format = resource->format; |
||
685 | blit.src.box.z = 0; |
||
686 | blit.src.box.depth = 1; |
||
687 | blit.src.box.x = 0; |
||
688 | blit.src.box.y = 0; |
||
689 | blit.src.box.width = resource->width0; |
||
690 | blit.src.box.height = resource->height0; |
||
691 | |||
692 | resource = This->present_buffers[0]; |
||
693 | |||
694 | blit.dst.resource = resource; |
||
695 | blit.dst.level = 0; |
||
696 | blit.dst.format = resource->format; |
||
697 | blit.dst.box.z = 0; |
||
698 | blit.dst.box.depth = 1; |
||
699 | blit.dst.box.x = 0; |
||
700 | blit.dst.box.y = 0; |
||
701 | blit.dst.box.width = resource->width0; |
||
702 | blit.dst.box.height = resource->height0; |
||
703 | |||
704 | blit.mask = PIPE_MASK_RGBA; |
||
705 | blit.filter = PIPE_TEX_FILTER_NEAREST; |
||
706 | blit.scissor_enable = FALSE; |
||
707 | |||
708 | This->pipe->blit(This->pipe, &blit); |
||
709 | } |
||
710 | |||
711 | if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD) |
||
712 | handle_draw_cursor_and_hud(This, resource); |
||
713 | |||
714 | fence = NULL; |
||
715 | This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME); |
||
716 | if (fence) { |
||
717 | swap_fences_push_back(This, fence); |
||
718 | This->screen->fence_reference(This->screen, &fence, NULL); |
||
719 | } |
||
720 | |||
721 | This->rendering_done = TRUE; |
||
722 | bypass_rendering: |
||
723 | |||
724 | if (dwFlags & D3DPRESENT_DONOTWAIT) { |
||
725 | UNTESTED(2); |
||
726 | BOOL still_draw = FALSE; |
||
727 | fence = swap_fences_see_front(This); |
||
728 | if (fence) { |
||
729 | still_draw = !This->screen->fence_signalled(This->screen, fence); |
||
730 | This->screen->fence_reference(This->screen, &fence, NULL); |
||
731 | } |
||
732 | if (still_draw) |
||
733 | return D3DERR_WASSTILLDRAWING; |
||
734 | } |
||
735 | |||
736 | if (This->present_buffers) |
||
737 | resource = This->present_buffers[0]; |
||
738 | else |
||
739 | resource = This->buffers[0]->base.resource; |
||
740 | This->pipe->flush_resource(This->pipe, resource); |
||
741 | |||
742 | if (!This->enable_threadpool) { |
||
743 | This->tasks[0]=NULL; |
||
744 | fence = swap_fences_pop_front(This); |
||
745 | if (fence) { |
||
746 | (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE); |
||
747 | This->screen->fence_reference(This->screen, &fence, NULL); |
||
748 | } |
||
749 | |||
750 | hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags); |
||
751 | |||
752 | if (FAILED(hr)) { UNTESTED(3);return hr; } |
||
753 | } else { |
||
754 | pend_present(This, hDestWindowOverride); |
||
755 | } |
||
756 | This->rendering_done = FALSE; |
||
757 | |||
758 | return D3D_OK; |
||
759 | } |
||
760 | |||
761 | HRESULT WINAPI |
||
762 | NineSwapChain9_Present( struct NineSwapChain9 *This, |
||
763 | const RECT *pSourceRect, |
||
764 | const RECT *pDestRect, |
||
765 | HWND hDestWindowOverride, |
||
766 | const RGNDATA *pDirtyRegion, |
||
767 | DWORD dwFlags ) |
||
768 | { |
||
769 | struct pipe_resource *res = NULL; |
||
770 | D3DWindowBuffer *handle_temp; |
||
771 | struct threadpool_task *task_temp; |
||
772 | int i; |
||
773 | HRESULT hr = present(This, pSourceRect, pDestRect, |
||
774 | hDestWindowOverride, pDirtyRegion, dwFlags); |
||
775 | |||
776 | DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " |
||
777 | "pDirtyRegion=%p dwFlags=%d\n", |
||
778 | This, pSourceRect, pDestRect, hDestWindowOverride, |
||
779 | pDirtyRegion,dwFlags); |
||
780 | |||
781 | if (hr == D3DERR_WASSTILLDRAWING) |
||
782 | return hr; |
||
783 | |||
784 | switch (This->params.SwapEffect) { |
||
785 | case D3DSWAPEFFECT_FLIP: |
||
786 | UNTESTED(4); |
||
787 | case D3DSWAPEFFECT_DISCARD: |
||
788 | /* rotate the queue */; |
||
789 | pipe_resource_reference(&res, This->buffers[0]->base.resource); |
||
790 | for (i = 1; i <= This->params.BackBufferCount; i++) { |
||
791 | NineSurface9_SetResourceResize(This->buffers[i - 1], |
||
792 | This->buffers[i]->base.resource); |
||
793 | } |
||
794 | NineSurface9_SetResourceResize( |
||
795 | This->buffers[This->params.BackBufferCount], res); |
||
796 | pipe_resource_reference(&res, NULL); |
||
797 | |||
798 | if (This->present_buffers) { |
||
799 | pipe_resource_reference(&res, This->present_buffers[0]); |
||
800 | for (i = 1; i <= This->params.BackBufferCount; i++) |
||
801 | pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); |
||
802 | pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res); |
||
803 | pipe_resource_reference(&res, NULL); |
||
804 | } |
||
805 | |||
806 | handle_temp = This->present_handles[0]; |
||
807 | for (i = 1; i <= This->params.BackBufferCount; i++) { |
||
808 | This->present_handles[i-1] = This->present_handles[i]; |
||
809 | } |
||
810 | This->present_handles[This->params.BackBufferCount] = handle_temp; |
||
811 | task_temp = This->tasks[0]; |
||
812 | for (i = 1; i <= This->params.BackBufferCount; i++) { |
||
813 | This->tasks[i-1] = This->tasks[i]; |
||
814 | } |
||
815 | This->tasks[This->params.BackBufferCount] = task_temp; |
||
816 | break; |
||
817 | |||
818 | case D3DSWAPEFFECT_COPY: |
||
819 | UNTESTED(5); |
||
820 | /* do nothing */ |
||
821 | break; |
||
822 | |||
823 | case D3DSWAPEFFECT_OVERLAY: |
||
824 | /* XXX not implemented */ |
||
825 | break; |
||
826 | |||
827 | case D3DSWAPEFFECT_FLIPEX: |
||
828 | /* XXX not implemented */ |
||
829 | break; |
||
830 | } |
||
831 | |||
832 | if (This->tasks[0]) |
||
833 | _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); |
||
834 | |||
835 | ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); |
||
836 | |||
837 | This->base.device->state.changed.group |= NINE_STATE_FB; |
||
838 | nine_update_state(This->base.device, NINE_STATE_FB); |
||
839 | |||
840 | return hr; |
||
841 | } |
||
842 | |||
843 | HRESULT WINAPI |
||
844 | NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This, |
||
845 | IDirect3DSurface9 *pDestSurface ) |
||
846 | { |
||
847 | struct NineSurface9 *dest_surface = NineSurface9(pDestSurface); |
||
848 | struct NineDevice9 *pDevice = This->base.device; |
||
849 | unsigned int width, height; |
||
850 | struct pipe_resource *temp_resource; |
||
851 | struct NineSurface9 *temp_surface; |
||
852 | D3DWindowBuffer *temp_handle; |
||
853 | D3DSURFACE_DESC desc; |
||
854 | HRESULT hr; |
||
855 | |||
856 | DBG("GetFrontBufferData: This=%p pDestSurface=%p\n", |
||
857 | This, pDestSurface); |
||
858 | |||
859 | width = dest_surface->desc.Width; |
||
860 | height = dest_surface->desc.Height; |
||
861 | |||
862 | /* Note: front window size and destination size are supposed |
||
863 | * to match. However it's not very clear what should get taken in Windowed |
||
864 | * mode. It may need a fix */ |
||
865 | create_present_buffer(This, width, height, &temp_resource, &temp_handle); |
||
866 | |||
867 | desc.Type = D3DRTYPE_SURFACE; |
||
868 | desc.Pool = D3DPOOL_DEFAULT; |
||
869 | desc.MultiSampleType = D3DMULTISAMPLE_NONE; |
||
870 | desc.MultiSampleQuality = 0; |
||
871 | desc.Width = width; |
||
872 | desc.Height = height; |
||
873 | /* NineSurface9_CopySurface needs same format. */ |
||
874 | desc.Format = dest_surface->desc.Format; |
||
875 | desc.Usage = D3DUSAGE_RENDERTARGET; |
||
876 | hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0, |
||
877 | 0, 0, &desc, &temp_surface); |
||
878 | pipe_resource_reference(&temp_resource, NULL); |
||
879 | if (FAILED(hr)) { |
||
880 | DBG("Failed to create temp FrontBuffer surface.\n"); |
||
881 | return hr; |
||
882 | } |
||
883 | |||
884 | ID3DPresent_FrontBufferCopy(This->present, temp_handle); |
||
885 | |||
886 | NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL); |
||
887 | |||
888 | ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle); |
||
889 | NineUnknown_Destroy(NineUnknown(temp_surface)); |
||
890 | |||
891 | return D3D_OK; |
||
892 | } |
||
893 | |||
894 | HRESULT WINAPI |
||
895 | NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This, |
||
896 | UINT iBackBuffer, |
||
897 | D3DBACKBUFFER_TYPE Type, |
||
898 | IDirect3DSurface9 **ppBackBuffer ) |
||
899 | { |
||
900 | DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n", |
||
901 | This, iBackBuffer, Type, ppBackBuffer); |
||
902 | (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO); |
||
903 | user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL); |
||
904 | user_assert(ppBackBuffer != NULL, E_POINTER); |
||
905 | |||
906 | NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer])); |
||
907 | *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer]; |
||
908 | return D3D_OK; |
||
909 | } |
||
910 | |||
911 | HRESULT WINAPI |
||
912 | NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This, |
||
913 | D3DRASTER_STATUS *pRasterStatus ) |
||
914 | { |
||
915 | DBG("GetRasterStatus: This=%p pRasterStatus=%p\n", |
||
916 | This, pRasterStatus); |
||
917 | user_assert(pRasterStatus != NULL, E_POINTER); |
||
918 | return ID3DPresent_GetRasterStatus(This->present, pRasterStatus); |
||
919 | } |
||
920 | |||
921 | HRESULT WINAPI |
||
922 | NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This, |
||
923 | D3DDISPLAYMODE *pMode ) |
||
924 | { |
||
925 | D3DDISPLAYMODEEX mode; |
||
926 | D3DDISPLAYROTATION rot; |
||
927 | HRESULT hr; |
||
928 | |||
929 | DBG("GetDisplayMode: This=%p pMode=%p\n", |
||
930 | This, pMode); |
||
931 | user_assert(pMode != NULL, E_POINTER); |
||
932 | |||
933 | hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot); |
||
934 | if (SUCCEEDED(hr)) { |
||
935 | pMode->Width = mode.Width; |
||
936 | pMode->Height = mode.Height; |
||
937 | pMode->RefreshRate = mode.RefreshRate; |
||
938 | pMode->Format = mode.Format; |
||
939 | } |
||
940 | return hr; |
||
941 | } |
||
942 | |||
943 | HRESULT WINAPI |
||
944 | NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This, |
||
945 | D3DPRESENT_PARAMETERS *pPresentationParameters ) |
||
946 | { |
||
947 | DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n", |
||
948 | This, pPresentationParameters); |
||
949 | user_assert(pPresentationParameters != NULL, E_POINTER); |
||
950 | *pPresentationParameters = This->params; |
||
951 | return D3D_OK; |
||
952 | } |
||
953 | |||
954 | IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = { |
||
955 | (void *)NineUnknown_QueryInterface, |
||
956 | (void *)NineUnknown_AddRef, |
||
957 | (void *)NineUnknown_Release, |
||
958 | (void *)NineSwapChain9_Present, |
||
959 | (void *)NineSwapChain9_GetFrontBufferData, |
||
960 | (void *)NineSwapChain9_GetBackBuffer, |
||
961 | (void *)NineSwapChain9_GetRasterStatus, |
||
962 | (void *)NineSwapChain9_GetDisplayMode, |
||
963 | (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */ |
||
964 | (void *)NineSwapChain9_GetPresentParameters |
||
965 | }; |
||
966 | |||
967 | static const GUID *NineSwapChain9_IIDs[] = { |
||
968 | &IID_IDirect3DSwapChain9, |
||
969 | &IID_IUnknown, |
||
970 | NULL |
||
971 | }; |
||
972 | |||
973 | HRESULT |
||
974 | NineSwapChain9_new( struct NineDevice9 *pDevice, |
||
975 | BOOL implicit, |
||
976 | ID3DPresent *pPresent, |
||
977 | D3DPRESENT_PARAMETERS *pPresentationParameters, |
||
978 | struct d3dadapter9_context *pCTX, |
||
979 | HWND hFocusWindow, |
||
980 | struct NineSwapChain9 **ppOut ) |
||
981 | { |
||
982 | NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */ |
||
983 | implicit, pPresent, pPresentationParameters, |
||
984 | pCTX, hFocusWindow, NULL); |
||
985 | }>=>=>=>=>>>>>>> |