Subversion Repositories Kolibri OS

Rev

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
}