17ec681f3Smrg/*
27ec681f3Smrg * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub
87ec681f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom
97ec681f3Smrg * the Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
197ec681f3Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
207ec681f3Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
217ec681f3Smrg * USE OR OTHER DEALINGS IN THE SOFTWARE. */
227ec681f3Smrg
237ec681f3Smrg#include "swapchain9.h"
247ec681f3Smrg#include "surface9.h"
257ec681f3Smrg#include "device9.h"
267ec681f3Smrg
277ec681f3Smrg#include "nine_helpers.h"
287ec681f3Smrg#include "nine_pipe.h"
297ec681f3Smrg#include "nine_dump.h"
307ec681f3Smrg
317ec681f3Smrg#include "util/u_atomic.h"
327ec681f3Smrg#include "util/u_inlines.h"
337ec681f3Smrg#include "util/u_surface.h"
347ec681f3Smrg#include "hud/hud_context.h"
357ec681f3Smrg#include "frontend/drm_driver.h"
367ec681f3Smrg
377ec681f3Smrg#include "threadpool.h"
387ec681f3Smrg
397ec681f3Smrg#define DBG_CHANNEL DBG_SWAPCHAIN
407ec681f3Smrg
417ec681f3Smrg#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
427ec681f3Smrg
437ec681f3SmrgHRESULT
447ec681f3SmrgNineSwapChain9_ctor( struct NineSwapChain9 *This,
457ec681f3Smrg                     struct NineUnknownParams *pParams,
467ec681f3Smrg                     BOOL implicit,
477ec681f3Smrg                     ID3DPresent *pPresent,
487ec681f3Smrg                     D3DPRESENT_PARAMETERS *pPresentationParameters,
497ec681f3Smrg                     struct d3dadapter9_context *pCTX,
507ec681f3Smrg                     HWND hFocusWindow,
517ec681f3Smrg                     D3DDISPLAYMODEEX *mode )
527ec681f3Smrg{
537ec681f3Smrg    HRESULT hr;
547ec681f3Smrg    int i;
557ec681f3Smrg
567ec681f3Smrg    DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
577ec681f3Smrg        This, pParams->device, pPresent, pCTX, hFocusWindow);
587ec681f3Smrg
597ec681f3Smrg    hr = NineUnknown_ctor(&This->base, pParams);
607ec681f3Smrg    if (FAILED(hr))
617ec681f3Smrg        return hr;
627ec681f3Smrg
637ec681f3Smrg    This->screen = NineDevice9_GetScreen(This->base.device);
647ec681f3Smrg    This->implicit = implicit;
657ec681f3Smrg    This->actx = pCTX;
667ec681f3Smrg    This->present = pPresent;
677ec681f3Smrg    This->mode = NULL;
687ec681f3Smrg
697ec681f3Smrg    ID3DPresent_AddRef(pPresent);
707ec681f3Smrg    if (This->base.device->minor_version_num > 2) {
717ec681f3Smrg        D3DPRESENT_PARAMETERS2 params2;
727ec681f3Smrg
737ec681f3Smrg        memset(&params2, 0, sizeof(D3DPRESENT_PARAMETERS2));
747ec681f3Smrg        params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release;
757ec681f3Smrg        params2.TearFreeDISCARD = This->actx->tearfree_discard;
767ec681f3Smrg        ID3DPresent_SetPresentParameters2(pPresent, &params2);
777ec681f3Smrg    }
787ec681f3Smrg
797ec681f3Smrg    if (!pPresentationParameters->hDeviceWindow)
807ec681f3Smrg        pPresentationParameters->hDeviceWindow = hFocusWindow;
817ec681f3Smrg
827ec681f3Smrg    This->rendering_done = FALSE;
837ec681f3Smrg    This->pool = NULL;
847ec681f3Smrg    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
857ec681f3Smrg        This->pending_presentation[i] = calloc(1, sizeof(BOOL));
867ec681f3Smrg        if (!This->pending_presentation[i])
877ec681f3Smrg            return E_OUTOFMEMORY;
887ec681f3Smrg    }
897ec681f3Smrg    return NineSwapChain9_Resize(This, pPresentationParameters, mode);
907ec681f3Smrg}
917ec681f3Smrg
927ec681f3Smrgstatic D3DWindowBuffer *
937ec681f3SmrgD3DWindowBuffer_create(struct NineSwapChain9 *This,
947ec681f3Smrg                       struct pipe_resource *resource,
957ec681f3Smrg                       int depth,
967ec681f3Smrg                       int for_frontbuffer_reading)
977ec681f3Smrg{
987ec681f3Smrg    D3DWindowBuffer *ret;
997ec681f3Smrg    struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device);
1007ec681f3Smrg    struct winsys_handle whandle;
1017ec681f3Smrg    int stride, dmaBufFd;
1027ec681f3Smrg    HRESULT hr;
1037ec681f3Smrg
1047ec681f3Smrg    memset(&whandle, 0, sizeof(whandle));
1057ec681f3Smrg    whandle.type = WINSYS_HANDLE_TYPE_FD;
1067ec681f3Smrg    This->screen->resource_get_handle(This->screen, pipe, resource,
1077ec681f3Smrg                                      &whandle,
1087ec681f3Smrg                                      for_frontbuffer_reading ?
1097ec681f3Smrg                                          PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE :
1107ec681f3Smrg                                          PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
1117ec681f3Smrg    nine_context_get_pipe_release(This->base.device);
1127ec681f3Smrg    stride = whandle.stride;
1137ec681f3Smrg    dmaBufFd = whandle.handle;
1147ec681f3Smrg    hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
1157ec681f3Smrg                                                  dmaBufFd,
1167ec681f3Smrg                                                  resource->width0,
1177ec681f3Smrg                                                  resource->height0,
1187ec681f3Smrg                                                  stride,
1197ec681f3Smrg                                                  depth,
1207ec681f3Smrg                                                  32,
1217ec681f3Smrg                                                  &ret);
1227ec681f3Smrg    assert (SUCCEEDED(hr));
1237ec681f3Smrg
1247ec681f3Smrg    if (FAILED(hr)) {
1257ec681f3Smrg        ERR("Failed to create new D3DWindowBufferFromDmaBuf\n");
1267ec681f3Smrg        return NULL;
1277ec681f3Smrg    }
1287ec681f3Smrg    return ret;
1297ec681f3Smrg}
1307ec681f3Smrg
1317ec681f3Smrgstatic void
1327ec681f3SmrgD3DWindowBuffer_release(struct NineSwapChain9 *This,
1337ec681f3Smrg                        D3DWindowBuffer *present_handle)
1347ec681f3Smrg{
1357ec681f3Smrg    int i;
1367ec681f3Smrg
1377ec681f3Smrg    /* IsBufferReleased API not available */
1387ec681f3Smrg    if (This->base.device->minor_version_num <= 2) {
1397ec681f3Smrg        ID3DPresent_DestroyD3DWindowBuffer(This->present, present_handle);
1407ec681f3Smrg        return;
1417ec681f3Smrg    }
1427ec681f3Smrg
1437ec681f3Smrg    /* Add it to the 'pending release' list */
1447ec681f3Smrg    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
1457ec681f3Smrg        if (!This->present_handles_pending_release[i]) {
1467ec681f3Smrg            This->present_handles_pending_release[i] = present_handle;
1477ec681f3Smrg            break;
1487ec681f3Smrg        }
1497ec681f3Smrg    }
1507ec681f3Smrg    if (i == (D3DPRESENT_BACK_BUFFERS_MAX_EX + 1)) {
1517ec681f3Smrg        ERR("Server not releasing buffers...\n");
1527ec681f3Smrg        assert(false);
1537ec681f3Smrg    }
1547ec681f3Smrg
1557ec681f3Smrg    /* Destroy elements of the list released by the server */
1567ec681f3Smrg    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
1577ec681f3Smrg        if (This->present_handles_pending_release[i] &&
1587ec681f3Smrg            ID3DPresent_IsBufferReleased(This->present, This->present_handles_pending_release[i])) {
1597ec681f3Smrg            /* WaitBufferReleased also waits the presentation feedback
1607ec681f3Smrg             * (which should arrive at about the same time),
1617ec681f3Smrg             * while IsBufferReleased doesn't. DestroyD3DWindowBuffer unfortunately
1627ec681f3Smrg             * checks it to release immediately all data, else the release
1637ec681f3Smrg             * is postponed for This->present release. To avoid leaks (we may handle
1647ec681f3Smrg             * a lot of resize), call WaitBufferReleased. */
1657ec681f3Smrg            ID3DPresent_WaitBufferReleased(This->present, This->present_handles_pending_release[i]);
1667ec681f3Smrg            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]);
1677ec681f3Smrg            This->present_handles_pending_release[i] = NULL;
1687ec681f3Smrg        }
1697ec681f3Smrg    }
1707ec681f3Smrg}
1717ec681f3Smrg
1727ec681f3Smrgstatic int
1737ec681f3SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
1747ec681f3Smrg                                            D3DPRESENT_PARAMETERS *pParams );
1757ec681f3Smrg
1767ec681f3SmrgHRESULT
1777ec681f3SmrgNineSwapChain9_Resize( struct NineSwapChain9 *This,
1787ec681f3Smrg                       D3DPRESENT_PARAMETERS *pParams,
1797ec681f3Smrg                       D3DDISPLAYMODEEX *mode )
1807ec681f3Smrg{
1817ec681f3Smrg    struct NineDevice9 *pDevice = This->base.device;
1827ec681f3Smrg    D3DSURFACE_DESC desc;
1837ec681f3Smrg    HRESULT hr;
1847ec681f3Smrg    struct pipe_resource *resource, tmplt;
1857ec681f3Smrg    enum pipe_format pf;
1867ec681f3Smrg    BOOL has_present_buffers = FALSE;
1877ec681f3Smrg    int depth;
1887ec681f3Smrg    unsigned i, oldBufferCount, newBufferCount;
1897ec681f3Smrg    D3DMULTISAMPLE_TYPE multisample_type;
1907ec681f3Smrg
1917ec681f3Smrg    DBG("This=%p pParams=%p\n", This, pParams);
1927ec681f3Smrg    user_assert(pParams != NULL, E_POINTER);
1937ec681f3Smrg    user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL);
1947ec681f3Smrg    user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) ||
1957ec681f3Smrg                (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL);
1967ec681f3Smrg    user_assert(pDevice->ex || pParams->BackBufferCount <=
1977ec681f3Smrg                D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL);
1987ec681f3Smrg    user_assert(!pDevice->ex || pParams->BackBufferCount <=
1997ec681f3Smrg                D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL);
2007ec681f3Smrg    user_assert(pDevice->ex ||
2017ec681f3Smrg                (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) ||
2027ec681f3Smrg                (pParams->SwapEffect == D3DSWAPEFFECT_COPY) ||
2037ec681f3Smrg                (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL);
2047ec681f3Smrg
2057ec681f3Smrg    DBG("pParams(%p):\n"
2067ec681f3Smrg        "BackBufferWidth: %u\n"
2077ec681f3Smrg        "BackBufferHeight: %u\n"
2087ec681f3Smrg        "BackBufferFormat: %s\n"
2097ec681f3Smrg        "BackBufferCount: %u\n"
2107ec681f3Smrg        "MultiSampleType: %u\n"
2117ec681f3Smrg        "MultiSampleQuality: %u\n"
2127ec681f3Smrg        "SwapEffect: %u\n"
2137ec681f3Smrg        "hDeviceWindow: %p\n"
2147ec681f3Smrg        "Windowed: %i\n"
2157ec681f3Smrg        "EnableAutoDepthStencil: %i\n"
2167ec681f3Smrg        "AutoDepthStencilFormat: %s\n"
2177ec681f3Smrg        "Flags: %s\n"
2187ec681f3Smrg        "FullScreen_RefreshRateInHz: %u\n"
2197ec681f3Smrg        "PresentationInterval: %x\n", pParams,
2207ec681f3Smrg        pParams->BackBufferWidth, pParams->BackBufferHeight,
2217ec681f3Smrg        d3dformat_to_string(pParams->BackBufferFormat),
2227ec681f3Smrg        pParams->BackBufferCount,
2237ec681f3Smrg        pParams->MultiSampleType, pParams->MultiSampleQuality,
2247ec681f3Smrg        pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
2257ec681f3Smrg        pParams->EnableAutoDepthStencil,
2267ec681f3Smrg        d3dformat_to_string(pParams->AutoDepthStencilFormat),
2277ec681f3Smrg        nine_D3DPRESENTFLAG_to_str(pParams->Flags),
2287ec681f3Smrg        pParams->FullScreen_RefreshRateInHz,
2297ec681f3Smrg        pParams->PresentationInterval);
2307ec681f3Smrg
2317ec681f3Smrg    if (pParams->BackBufferCount == 0) {
2327ec681f3Smrg        pParams->BackBufferCount = 1;
2337ec681f3Smrg    }
2347ec681f3Smrg
2357ec681f3Smrg    if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
2367ec681f3Smrg        pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
2377ec681f3Smrg    }
2387ec681f3Smrg
2397ec681f3Smrg    This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
2407ec681f3Smrg    /* +1 because we add the fence of the current buffer before popping an old one */
2417ec681f3Smrg    if (This->desired_fences > DRI_SWAP_FENCES_MAX)
2427ec681f3Smrg        This->desired_fences = DRI_SWAP_FENCES_MAX;
2437ec681f3Smrg
2447ec681f3Smrg    if (This->actx->vblank_mode == 0)
2457ec681f3Smrg        pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2467ec681f3Smrg    else if (This->actx->vblank_mode == 3)
2477ec681f3Smrg        pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
2487ec681f3Smrg
2497ec681f3Smrg    if (mode && This->mode) {
2507ec681f3Smrg        *(This->mode) = *mode;
2517ec681f3Smrg    } else if (mode) {
2527ec681f3Smrg        This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
2537ec681f3Smrg        memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
2547ec681f3Smrg    } else {
2557ec681f3Smrg        free(This->mode);
2567ec681f3Smrg        This->mode = NULL;
2577ec681f3Smrg    }
2587ec681f3Smrg
2597ec681f3Smrg    /* Note: It is the role of the backend to fill if necessary
2607ec681f3Smrg     * BackBufferWidth and BackBufferHeight */
2617ec681f3Smrg    hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
2627ec681f3Smrg    if (hr != D3D_OK)
2637ec681f3Smrg        return hr;
2647ec681f3Smrg
2657ec681f3Smrg    oldBufferCount = This->num_back_buffers;
2667ec681f3Smrg    newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams);
2677ec681f3Smrg
2687ec681f3Smrg    multisample_type = pParams->MultiSampleType;
2697ec681f3Smrg
2707ec681f3Smrg    /* Map MultiSampleQuality to MultiSampleType */
2717ec681f3Smrg    hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat,
2727ec681f3Smrg                                   &multisample_type,
2737ec681f3Smrg                                   pParams->MultiSampleQuality,
2747ec681f3Smrg                                   NULL);
2757ec681f3Smrg    if (FAILED(hr)) {
2767ec681f3Smrg        return hr;
2777ec681f3Smrg    }
2787ec681f3Smrg
2797ec681f3Smrg    pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat,
2807ec681f3Smrg                                     PIPE_TEXTURE_2D, multisample_type,
2817ec681f3Smrg                                     PIPE_BIND_RENDER_TARGET, FALSE, FALSE);
2827ec681f3Smrg
2837ec681f3Smrg    if (This->actx->linear_framebuffer ||
2847ec681f3Smrg        (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
2857ec681f3Smrg        pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
2867ec681f3Smrg        pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
2877ec681f3Smrg        multisample_type >= 2 ||
2887ec681f3Smrg        (This->actx->ref && This->actx->ref == This->screen))
2897ec681f3Smrg        has_present_buffers = TRUE;
2907ec681f3Smrg
2917ec681f3Smrg    /* Note: the buffer depth has to match the window depth.
2927ec681f3Smrg     * In practice, ARGB buffers can be used with windows
2937ec681f3Smrg     * of depth 24. Windows of depth 32 are extremely rare.
2947ec681f3Smrg     * So even if the buffer is ARGB, say it is depth 24.
2957ec681f3Smrg     * It is common practice, for example that's how
2967ec681f3Smrg     * glamor implements depth 24.
2977ec681f3Smrg     * TODO: handle windows with other depths. Not possible in the short term.
2987ec681f3Smrg     * For example 16 bits.*/
2997ec681f3Smrg    depth = 24;
3007ec681f3Smrg
3017ec681f3Smrg    memset(&tmplt, 0, sizeof(tmplt));
3027ec681f3Smrg    tmplt.target = PIPE_TEXTURE_2D;
3037ec681f3Smrg    tmplt.width0 = pParams->BackBufferWidth;
3047ec681f3Smrg    tmplt.height0 = pParams->BackBufferHeight;
3057ec681f3Smrg    tmplt.depth0 = 1;
3067ec681f3Smrg    tmplt.last_level = 0;
3077ec681f3Smrg    tmplt.array_size = 1;
3087ec681f3Smrg    tmplt.usage = PIPE_USAGE_DEFAULT;
3097ec681f3Smrg    tmplt.flags = 0;
3107ec681f3Smrg
3117ec681f3Smrg    desc.Type = D3DRTYPE_SURFACE;
3127ec681f3Smrg    desc.Pool = D3DPOOL_DEFAULT;
3137ec681f3Smrg    desc.MultiSampleType = pParams->MultiSampleType;
3147ec681f3Smrg    desc.MultiSampleQuality = pParams->MultiSampleQuality;
3157ec681f3Smrg    desc.Width = pParams->BackBufferWidth;
3167ec681f3Smrg    desc.Height = pParams->BackBufferHeight;
3177ec681f3Smrg
3187ec681f3Smrg    for (i = 0; i < oldBufferCount; i++) {
3197ec681f3Smrg        if (This->tasks[i])
3207ec681f3Smrg            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i]));
3217ec681f3Smrg    }
3227ec681f3Smrg    memset(This->tasks, 0, sizeof(This->tasks));
3237ec681f3Smrg
3247ec681f3Smrg    if (This->pool) {
3257ec681f3Smrg        _mesa_threadpool_destroy(This, This->pool);
3267ec681f3Smrg        This->pool = NULL;
3277ec681f3Smrg    }
3287ec681f3Smrg    This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
3297ec681f3Smrg    if (This->enable_threadpool)
3307ec681f3Smrg        This->pool = _mesa_threadpool_create(This);
3317ec681f3Smrg    if (!This->pool)
3327ec681f3Smrg        This->enable_threadpool = FALSE;
3337ec681f3Smrg
3347ec681f3Smrg    for (i = 0; i < oldBufferCount; i++) {
3357ec681f3Smrg        D3DWindowBuffer_release(This, This->present_handles[i]);
3367ec681f3Smrg        This->present_handles[i] = NULL;
3377ec681f3Smrg        if (This->present_buffers[i])
3387ec681f3Smrg            pipe_resource_reference(&(This->present_buffers[i]), NULL);
3397ec681f3Smrg    }
3407ec681f3Smrg
3417ec681f3Smrg    if (newBufferCount != oldBufferCount) {
3427ec681f3Smrg        for (i = newBufferCount; i < oldBufferCount;
3437ec681f3Smrg             ++i)
3447ec681f3Smrg            NineUnknown_Detach(NineUnknown(This->buffers[i]));
3457ec681f3Smrg
3467ec681f3Smrg        for (i = oldBufferCount; i < newBufferCount; ++i) {
3477ec681f3Smrg            This->buffers[i] = NULL;
3487ec681f3Smrg            This->present_handles[i] = NULL;
3497ec681f3Smrg        }
3507ec681f3Smrg    }
3517ec681f3Smrg    This->num_back_buffers = newBufferCount;
3527ec681f3Smrg
3537ec681f3Smrg    for (i = 0; i < newBufferCount; ++i) {
3547ec681f3Smrg        tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
3557ec681f3Smrg        tmplt.nr_samples = multisample_type;
3567ec681f3Smrg        tmplt.nr_storage_samples = multisample_type;
3577ec681f3Smrg        if (!has_present_buffers)
3587ec681f3Smrg            tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS;
3597ec681f3Smrg        tmplt.format = d3d9_to_pipe_format_checked(This->screen,
3607ec681f3Smrg                                                   pParams->BackBufferFormat,
3617ec681f3Smrg                                                   PIPE_TEXTURE_2D,
3627ec681f3Smrg                                                   tmplt.nr_samples,
3637ec681f3Smrg                                                   tmplt.bind, FALSE, FALSE);
3647ec681f3Smrg        if (tmplt.format == PIPE_FORMAT_NONE)
3657ec681f3Smrg            return D3DERR_INVALIDCALL;
3667ec681f3Smrg        resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
3677ec681f3Smrg        if (!resource) {
3687ec681f3Smrg            DBG("Failed to create pipe_resource.\n");
3697ec681f3Smrg            return D3DERR_OUTOFVIDEOMEMORY;
3707ec681f3Smrg        }
3717ec681f3Smrg        if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
3727ec681f3Smrg            resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
3737ec681f3Smrg        if (This->buffers[i]) {
3747ec681f3Smrg            NineSurface9_SetMultiSampleType(This->buffers[i], desc.MultiSampleType);
3757ec681f3Smrg            NineSurface9_SetResourceResize(This->buffers[i], resource);
3767ec681f3Smrg            if (has_present_buffers)
3777ec681f3Smrg                pipe_resource_reference(&resource, NULL);
3787ec681f3Smrg        } else {
3797ec681f3Smrg            desc.Format = pParams->BackBufferFormat;
3807ec681f3Smrg            desc.Usage = D3DUSAGE_RENDERTARGET;
3817ec681f3Smrg            hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0,
3827ec681f3Smrg                                  0, 0, &desc, &This->buffers[i]);
3837ec681f3Smrg            if (has_present_buffers)
3847ec681f3Smrg                pipe_resource_reference(&resource, NULL);
3857ec681f3Smrg            if (FAILED(hr)) {
3867ec681f3Smrg                DBG("Failed to create RT surface.\n");
3877ec681f3Smrg                return hr;
3887ec681f3Smrg            }
3897ec681f3Smrg            This->buffers[i]->base.base.forward = FALSE;
3907ec681f3Smrg        }
3917ec681f3Smrg        if (has_present_buffers) {
3927ec681f3Smrg            tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
3937ec681f3Smrg            tmplt.bind = NINE_BIND_PRESENTBUFFER_FLAGS;
3947ec681f3Smrg            tmplt.nr_samples = 0;
3957ec681f3Smrg            tmplt.nr_storage_samples = 0;
3967ec681f3Smrg            if (This->actx->linear_framebuffer)
3977ec681f3Smrg                tmplt.bind |= PIPE_BIND_LINEAR;
3987ec681f3Smrg            if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
3997ec681f3Smrg                tmplt.bind |= PIPE_BIND_RENDER_TARGET;
4007ec681f3Smrg            resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
4017ec681f3Smrg            pipe_resource_reference(&(This->present_buffers[i]), resource);
4027ec681f3Smrg        }
4037ec681f3Smrg        This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth, false);
4047ec681f3Smrg        pipe_resource_reference(&resource, NULL);
4057ec681f3Smrg        if (!This->present_handles[i]) {
4067ec681f3Smrg            return D3DERR_DRIVERINTERNALERROR;
4077ec681f3Smrg        }
4087ec681f3Smrg    }
4097ec681f3Smrg    if (pParams->EnableAutoDepthStencil) {
4107ec681f3Smrg        tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat);
4117ec681f3Smrg        tmplt.nr_samples = multisample_type;
4127ec681f3Smrg        tmplt.nr_storage_samples = multisample_type;
4137ec681f3Smrg        tmplt.format = d3d9_to_pipe_format_checked(This->screen,
4147ec681f3Smrg                                                   pParams->AutoDepthStencilFormat,
4157ec681f3Smrg                                                   PIPE_TEXTURE_2D,
4167ec681f3Smrg                                                   tmplt.nr_samples,
4177ec681f3Smrg                                                   tmplt.bind,
4187ec681f3Smrg                                                   FALSE, FALSE);
4197ec681f3Smrg
4207ec681f3Smrg        if (tmplt.format == PIPE_FORMAT_NONE)
4217ec681f3Smrg            return D3DERR_INVALIDCALL;
4227ec681f3Smrg
4237ec681f3Smrg        if (This->zsbuf) {
4247ec681f3Smrg            resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
4257ec681f3Smrg            if (!resource) {
4267ec681f3Smrg                DBG("Failed to create pipe_resource for depth buffer.\n");
4277ec681f3Smrg                return D3DERR_OUTOFVIDEOMEMORY;
4287ec681f3Smrg            }
4297ec681f3Smrg
4307ec681f3Smrg            NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType);
4317ec681f3Smrg            NineSurface9_SetResourceResize(This->zsbuf, resource);
4327ec681f3Smrg            pipe_resource_reference(&resource, NULL);
4337ec681f3Smrg        } else {
4347ec681f3Smrg            hr = NineDevice9_CreateDepthStencilSurface(pDevice,
4357ec681f3Smrg                                                       pParams->BackBufferWidth,
4367ec681f3Smrg                                                       pParams->BackBufferHeight,
4377ec681f3Smrg                                                       pParams->AutoDepthStencilFormat,
4387ec681f3Smrg                                                       pParams->MultiSampleType,
4397ec681f3Smrg                                                       pParams->MultiSampleQuality,
4407ec681f3Smrg                                                       0,
4417ec681f3Smrg                                                       (IDirect3DSurface9 **)&This->zsbuf,
4427ec681f3Smrg                                                       NULL);
4437ec681f3Smrg            if (FAILED(hr)) {
4447ec681f3Smrg                DBG("Failed to create ZS surface.\n");
4457ec681f3Smrg                return hr;
4467ec681f3Smrg            }
4477ec681f3Smrg            NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf));
4487ec681f3Smrg        }
4497ec681f3Smrg    }
4507ec681f3Smrg
4517ec681f3Smrg    This->params = *pParams;
4527ec681f3Smrg
4537ec681f3Smrg    return D3D_OK;
4547ec681f3Smrg}
4557ec681f3Smrg
4567ec681f3Smrg/* Throttling: code adapted from the dri frontend */
4577ec681f3Smrg
4587ec681f3Smrg/**
4597ec681f3Smrg * swap_fences_pop_front - pull a fence from the throttle queue
4607ec681f3Smrg *
4617ec681f3Smrg * If the throttle queue is filled to the desired number of fences,
4627ec681f3Smrg * pull fences off the queue until the number is less than the desired
4637ec681f3Smrg * number of fences, and return the last fence pulled.
4647ec681f3Smrg */
4657ec681f3Smrgstatic struct pipe_fence_handle *
4667ec681f3Smrgswap_fences_pop_front(struct NineSwapChain9 *This)
4677ec681f3Smrg{
4687ec681f3Smrg    struct pipe_screen *screen = This->screen;
4697ec681f3Smrg    struct pipe_fence_handle *fence = NULL;
4707ec681f3Smrg
4717ec681f3Smrg    if (This->desired_fences == 0)
4727ec681f3Smrg        return NULL;
4737ec681f3Smrg
4747ec681f3Smrg    if (This->cur_fences >= This->desired_fences) {
4757ec681f3Smrg        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
4767ec681f3Smrg        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
4777ec681f3Smrg        This->tail &= DRI_SWAP_FENCES_MASK;
4787ec681f3Smrg        --This->cur_fences;
4797ec681f3Smrg    }
4807ec681f3Smrg    return fence;
4817ec681f3Smrg}
4827ec681f3Smrg
4837ec681f3Smrg
4847ec681f3Smrg/**
4857ec681f3Smrg * swap_fences_see_front - same than swap_fences_pop_front without
4867ec681f3Smrg * pulling
4877ec681f3Smrg *
4887ec681f3Smrg */
4897ec681f3Smrg
4907ec681f3Smrgstatic struct pipe_fence_handle *
4917ec681f3Smrgswap_fences_see_front(struct NineSwapChain9 *This)
4927ec681f3Smrg{
4937ec681f3Smrg    struct pipe_screen *screen = This->screen;
4947ec681f3Smrg    struct pipe_fence_handle *fence = NULL;
4957ec681f3Smrg
4967ec681f3Smrg    if (This->desired_fences == 0)
4977ec681f3Smrg        return NULL;
4987ec681f3Smrg
4997ec681f3Smrg    if (This->cur_fences >= This->desired_fences) {
5007ec681f3Smrg        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
5017ec681f3Smrg    }
5027ec681f3Smrg    return fence;
5037ec681f3Smrg}
5047ec681f3Smrg
5057ec681f3Smrg
5067ec681f3Smrg/**
5077ec681f3Smrg * swap_fences_push_back - push a fence onto the throttle queue at the back
5087ec681f3Smrg *
5097ec681f3Smrg * push a fence onto the throttle queue and pull fences of the queue
5107ec681f3Smrg * so that the desired number of fences are on the queue.
5117ec681f3Smrg */
5127ec681f3Smrgstatic void
5137ec681f3Smrgswap_fences_push_back(struct NineSwapChain9 *This,
5147ec681f3Smrg                      struct pipe_fence_handle *fence)
5157ec681f3Smrg{
5167ec681f3Smrg    struct pipe_screen *screen = This->screen;
5177ec681f3Smrg
5187ec681f3Smrg    if (!fence || This->desired_fences == 0)
5197ec681f3Smrg        return;
5207ec681f3Smrg
5217ec681f3Smrg    while(This->cur_fences == This->desired_fences)
5227ec681f3Smrg        swap_fences_pop_front(This);
5237ec681f3Smrg
5247ec681f3Smrg    This->cur_fences++;
5257ec681f3Smrg    screen->fence_reference(screen, &This->swap_fences[This->head++],
5267ec681f3Smrg                            fence);
5277ec681f3Smrg    This->head &= DRI_SWAP_FENCES_MASK;
5287ec681f3Smrg}
5297ec681f3Smrg
5307ec681f3Smrg
5317ec681f3Smrg/**
5327ec681f3Smrg * swap_fences_unref - empty the throttle queue
5337ec681f3Smrg *
5347ec681f3Smrg * pulls fences of the throttle queue until it is empty.
5357ec681f3Smrg */
5367ec681f3Smrgstatic void
5377ec681f3Smrgswap_fences_unref(struct NineSwapChain9 *This)
5387ec681f3Smrg{
5397ec681f3Smrg    struct pipe_screen *screen = This->screen;
5407ec681f3Smrg
5417ec681f3Smrg    while(This->cur_fences) {
5427ec681f3Smrg        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
5437ec681f3Smrg        This->tail &= DRI_SWAP_FENCES_MASK;
5447ec681f3Smrg        --This->cur_fences;
5457ec681f3Smrg    }
5467ec681f3Smrg}
5477ec681f3Smrg
5487ec681f3Smrgvoid
5497ec681f3SmrgNineSwapChain9_dtor( struct NineSwapChain9 *This )
5507ec681f3Smrg{
5517ec681f3Smrg    unsigned i;
5527ec681f3Smrg
5537ec681f3Smrg    DBG("This=%p\n", This);
5547ec681f3Smrg
5557ec681f3Smrg    if (This->pool)
5567ec681f3Smrg        _mesa_threadpool_destroy(This, This->pool);
5577ec681f3Smrg
5587ec681f3Smrg    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
5597ec681f3Smrg        if (This->pending_presentation[i])
5607ec681f3Smrg            FREE(This->pending_presentation[i]);
5617ec681f3Smrg    }
5627ec681f3Smrg
5637ec681f3Smrg    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
5647ec681f3Smrg        if (This->present_handles_pending_release[i])
5657ec681f3Smrg            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]);
5667ec681f3Smrg    }
5677ec681f3Smrg
5687ec681f3Smrg    for (i = 0; i < This->num_back_buffers; i++) {
5697ec681f3Smrg        if (This->buffers[i])
5707ec681f3Smrg            NineUnknown_Detach(NineUnknown(This->buffers[i]));
5717ec681f3Smrg        if (This->present_handles[i])
5727ec681f3Smrg            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
5737ec681f3Smrg        if (This->present_buffers[i])
5747ec681f3Smrg            pipe_resource_reference(&(This->present_buffers[i]), NULL);
5757ec681f3Smrg    }
5767ec681f3Smrg    if (This->zsbuf)
5777ec681f3Smrg        NineUnknown_Unbind(NineUnknown(This->zsbuf));
5787ec681f3Smrg
5797ec681f3Smrg    if (This->present)
5807ec681f3Smrg        ID3DPresent_Release(This->present);
5817ec681f3Smrg
5827ec681f3Smrg    swap_fences_unref(This);
5837ec681f3Smrg    NineUnknown_dtor(&This->base);
5847ec681f3Smrg}
5857ec681f3Smrg
5867ec681f3Smrgstatic void
5877ec681f3Smrgcreate_present_buffer( struct NineSwapChain9 *This,
5887ec681f3Smrg                       unsigned int width, unsigned int height,
5897ec681f3Smrg                       struct pipe_resource **resource,
5907ec681f3Smrg                       D3DWindowBuffer **present_handle)
5917ec681f3Smrg{
5927ec681f3Smrg    struct pipe_resource tmplt;
5937ec681f3Smrg
5947ec681f3Smrg    memset(&tmplt, 0, sizeof(tmplt));
5957ec681f3Smrg    tmplt.target = PIPE_TEXTURE_2D;
5967ec681f3Smrg    tmplt.width0 = width;
5977ec681f3Smrg    tmplt.height0 = height;
5987ec681f3Smrg    tmplt.depth0 = 1;
5997ec681f3Smrg    tmplt.last_level = 0;
6007ec681f3Smrg    tmplt.array_size = 1;
6017ec681f3Smrg    tmplt.usage = PIPE_USAGE_DEFAULT;
6027ec681f3Smrg    tmplt.flags = 0;
6037ec681f3Smrg    tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
6047ec681f3Smrg    tmplt.bind = NINE_BIND_BACKBUFFER_FLAGS |
6057ec681f3Smrg                 NINE_BIND_PRESENTBUFFER_FLAGS;
6067ec681f3Smrg    tmplt.nr_samples = 0;
6077ec681f3Smrg    if (This->actx->linear_framebuffer)
6087ec681f3Smrg        tmplt.bind |= PIPE_BIND_LINEAR;
6097ec681f3Smrg    *resource = nine_resource_create_with_retry(This->base.device, This->screen, &tmplt);
6107ec681f3Smrg
6117ec681f3Smrg    *present_handle = D3DWindowBuffer_create(This, *resource, 24, true);
6127ec681f3Smrg
6137ec681f3Smrg    if (!*present_handle) {
6147ec681f3Smrg        pipe_resource_reference(resource, NULL);
6157ec681f3Smrg    }
6167ec681f3Smrg}
6177ec681f3Smrg
6187ec681f3Smrgstatic void
6197ec681f3Smrghandle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
6207ec681f3Smrg{
6217ec681f3Smrg    struct NineDevice9 *device = This->base.device;
6227ec681f3Smrg    struct pipe_blit_info blit;
6237ec681f3Smrg    struct pipe_context *pipe;
6247ec681f3Smrg
6257ec681f3Smrg    if (device->cursor.software && device->cursor.visible && device->cursor.w) {
6267ec681f3Smrg        memset(&blit, 0, sizeof(blit));
6277ec681f3Smrg        blit.src.resource = device->cursor.image;
6287ec681f3Smrg        blit.src.level = 0;
6297ec681f3Smrg        blit.src.format = device->cursor.image->format;
6307ec681f3Smrg        blit.src.box.x = 0;
6317ec681f3Smrg        blit.src.box.y = 0;
6327ec681f3Smrg        blit.src.box.z = 0;
6337ec681f3Smrg        blit.src.box.depth = 1;
6347ec681f3Smrg        blit.src.box.width = device->cursor.w;
6357ec681f3Smrg        blit.src.box.height = device->cursor.h;
6367ec681f3Smrg
6377ec681f3Smrg        blit.dst.resource = resource;
6387ec681f3Smrg        blit.dst.level = 0;
6397ec681f3Smrg        blit.dst.format = resource->format;
6407ec681f3Smrg        blit.dst.box.z = 0;
6417ec681f3Smrg        blit.dst.box.depth = 1;
6427ec681f3Smrg
6437ec681f3Smrg        blit.mask = PIPE_MASK_RGBA;
6447ec681f3Smrg        blit.filter = PIPE_TEX_FILTER_NEAREST;
6457ec681f3Smrg        blit.scissor_enable = FALSE;
6467ec681f3Smrg
6477ec681f3Smrg        /* NOTE: blit messes up when box.x + box.width < 0, fix driver
6487ec681f3Smrg         * NOTE2: device->cursor.pos contains coordinates relative to the screen.
6497ec681f3Smrg         * This happens to be also the position of the cursor when we are fullscreen.
6507ec681f3Smrg         * We don't use sw cursor for Windowed mode */
6517ec681f3Smrg        blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
6527ec681f3Smrg        blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
6537ec681f3Smrg        blit.dst.box.width = blit.src.box.width;
6547ec681f3Smrg        blit.dst.box.height = blit.src.box.height;
6557ec681f3Smrg
6567ec681f3Smrg        DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
6577ec681f3Smrg            blit.src.box.width, blit.src.box.height,
6587ec681f3Smrg            blit.dst.box.x, blit.dst.box.y);
6597ec681f3Smrg
6607ec681f3Smrg        blit.alpha_blend = TRUE;
6617ec681f3Smrg        pipe = NineDevice9_GetPipe(This->base.device);
6627ec681f3Smrg        pipe->blit(pipe, &blit);
6637ec681f3Smrg    }
6647ec681f3Smrg
6657ec681f3Smrg    if (device->hud && resource) {
6667ec681f3Smrg        /* Implicit use of context pipe */
6677ec681f3Smrg        (void)NineDevice9_GetPipe(This->base.device);
6687ec681f3Smrg        hud_run(device->hud, NULL, resource); /* XXX: no offset */
6697ec681f3Smrg        /* HUD doesn't clobber stipple */
6707ec681f3Smrg        nine_state_restore_non_cso(device);
6717ec681f3Smrg    }
6727ec681f3Smrg}
6737ec681f3Smrg
6747ec681f3Smrgstruct end_present_struct {
6757ec681f3Smrg    struct pipe_screen *screen;
6767ec681f3Smrg    struct pipe_fence_handle *fence_to_wait;
6777ec681f3Smrg    ID3DPresent *present;
6787ec681f3Smrg    D3DWindowBuffer *present_handle;
6797ec681f3Smrg    BOOL *pending_presentation;
6807ec681f3Smrg    HWND hDestWindowOverride;
6817ec681f3Smrg};
6827ec681f3Smrg
6837ec681f3Smrgstatic void work_present(void *data)
6847ec681f3Smrg{
6857ec681f3Smrg    struct end_present_struct *work = data;
6867ec681f3Smrg    if (work->fence_to_wait) {
6877ec681f3Smrg        (void) work->screen->fence_finish(work->screen, NULL, work->fence_to_wait, PIPE_TIMEOUT_INFINITE);
6887ec681f3Smrg        work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL);
6897ec681f3Smrg    }
6907ec681f3Smrg    ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0);
6917ec681f3Smrg    p_atomic_set(work->pending_presentation, FALSE);
6927ec681f3Smrg    free(work);
6937ec681f3Smrg}
6947ec681f3Smrg
6957ec681f3Smrgstatic void pend_present(struct NineSwapChain9 *This,
6967ec681f3Smrg                         struct pipe_fence_handle *fence,
6977ec681f3Smrg                         HWND hDestWindowOverride)
6987ec681f3Smrg{
6997ec681f3Smrg    struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct));
7007ec681f3Smrg
7017ec681f3Smrg    work->screen = This->screen;
7027ec681f3Smrg    This->screen->fence_reference(This->screen, &work->fence_to_wait, fence);
7037ec681f3Smrg    work->present = This->present;
7047ec681f3Smrg    work->present_handle = This->present_handles[0];
7057ec681f3Smrg    work->hDestWindowOverride = hDestWindowOverride;
7067ec681f3Smrg    work->pending_presentation = This->pending_presentation[0];
7077ec681f3Smrg    p_atomic_set(work->pending_presentation, TRUE);
7087ec681f3Smrg    This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work);
7097ec681f3Smrg
7107ec681f3Smrg    return;
7117ec681f3Smrg}
7127ec681f3Smrg
7137ec681f3Smrgstatic inline HRESULT
7147ec681f3Smrgpresent( struct NineSwapChain9 *This,
7157ec681f3Smrg         const RECT *pSourceRect,
7167ec681f3Smrg         const RECT *pDestRect,
7177ec681f3Smrg         HWND hDestWindowOverride,
7187ec681f3Smrg         const RGNDATA *pDirtyRegion,
7197ec681f3Smrg         DWORD dwFlags )
7207ec681f3Smrg{
7217ec681f3Smrg    struct pipe_context *pipe;
7227ec681f3Smrg    struct pipe_resource *resource;
7237ec681f3Smrg    struct pipe_fence_handle *fence;
7247ec681f3Smrg    HRESULT hr;
7257ec681f3Smrg    struct pipe_blit_info blit;
7267ec681f3Smrg    int target_width, target_height, target_depth, i;
7277ec681f3Smrg    RECT source_rect;
7287ec681f3Smrg    RECT dest_rect;
7297ec681f3Smrg
7307ec681f3Smrg    DBG("present: This=%p pSourceRect=%p pDestRect=%p "
7317ec681f3Smrg        "pDirtyRegion=%p hDestWindowOverride=%p"
7327ec681f3Smrg        "dwFlags=%d resource=%p\n",
7337ec681f3Smrg        This, pSourceRect, pDestRect, pDirtyRegion,
7347ec681f3Smrg        hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
7357ec681f3Smrg
7367ec681f3Smrg    /* We can choose to only update pDirtyRegion, but the backend can choose
7377ec681f3Smrg     * to update everything. Let's ignore */
7387ec681f3Smrg    (void) pDirtyRegion;
7397ec681f3Smrg
7407ec681f3Smrg    resource = This->buffers[0]->base.resource;
7417ec681f3Smrg
7427ec681f3Smrg    if (pSourceRect) {
7437ec681f3Smrg        DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
7447ec681f3Smrg            pSourceRect->left, pSourceRect->right,
7457ec681f3Smrg            pSourceRect->top, pSourceRect->bottom);
7467ec681f3Smrg        source_rect = *pSourceRect;
7477ec681f3Smrg        if (source_rect.top == 0 &&
7487ec681f3Smrg            source_rect.left == 0 &&
7497ec681f3Smrg            source_rect.bottom == resource->height0 &&
7507ec681f3Smrg            source_rect.right == resource->width0)
7517ec681f3Smrg            pSourceRect = NULL;
7527ec681f3Smrg        /* TODO: Handle more of pSourceRect.
7537ec681f3Smrg         * Currently we should support:
7547ec681f3Smrg         * . When there is no pSourceRect
7557ec681f3Smrg         * . When pSourceRect is the full buffer.
7567ec681f3Smrg         */
7577ec681f3Smrg    }
7587ec681f3Smrg    if (pDestRect) {
7597ec681f3Smrg        DBG("pDestRect = (%u..%u)x(%u..%u)\n",
7607ec681f3Smrg            pDestRect->left, pDestRect->right,
7617ec681f3Smrg            pDestRect->top, pDestRect->bottom);
7627ec681f3Smrg        dest_rect = *pDestRect;
7637ec681f3Smrg    }
7647ec681f3Smrg
7657ec681f3Smrg    if (This->rendering_done)
7667ec681f3Smrg        goto bypass_rendering;
7677ec681f3Smrg
7687ec681f3Smrg    if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
7697ec681f3Smrg        handle_draw_cursor_and_hud(This, resource);
7707ec681f3Smrg
7717ec681f3Smrg    hr = ID3DPresent_GetWindowInfo(This->present, hDestWindowOverride, &target_width, &target_height, &target_depth);
7727ec681f3Smrg    (void)target_depth;
7737ec681f3Smrg
7747ec681f3Smrg    /* Can happen with old Wine (presentation can still succeed),
7757ec681f3Smrg     * or at window destruction.
7767ec681f3Smrg     * Also disable for very old wine as D3DWindowBuffer_release
7777ec681f3Smrg     * cannot do the DestroyD3DWindowBuffer workaround. */
7787ec681f3Smrg    if (FAILED(hr) || target_width == 0 || target_height == 0 ||
7797ec681f3Smrg        This->base.device->minor_version_num <= 2) {
7807ec681f3Smrg        target_width = resource->width0;
7817ec681f3Smrg        target_height = resource->height0;
7827ec681f3Smrg    }
7837ec681f3Smrg
7847ec681f3Smrg    if (pDestRect) {
7857ec681f3Smrg        dest_rect.top = MAX2(0, dest_rect.top);
7867ec681f3Smrg        dest_rect.left = MAX2(0, dest_rect.left);
7877ec681f3Smrg        dest_rect.bottom = MIN2(target_height, dest_rect.bottom);
7887ec681f3Smrg        dest_rect.right = MIN2(target_width, dest_rect.right);
7897ec681f3Smrg        target_height = dest_rect.bottom - dest_rect.top;
7907ec681f3Smrg        target_width = dest_rect.right - dest_rect.left;
7917ec681f3Smrg    }
7927ec681f3Smrg
7937ec681f3Smrg    /* Switch to using presentation buffers on window resize.
7947ec681f3Smrg     * Note: Most apps should resize the d3d back buffers when
7957ec681f3Smrg     * a window resize is detected, which will result in a call to
7967ec681f3Smrg     * NineSwapChain9_Resize. Thus everything will get released,
7977ec681f3Smrg     * and it will switch back to not using separate presentation
7987ec681f3Smrg     * buffers. */
7997ec681f3Smrg    if (!This->present_buffers[0] &&
8007ec681f3Smrg        (target_width != resource->width0 || target_height != resource->height0)) {
8017ec681f3Smrg        BOOL failure = false;
8027ec681f3Smrg        struct pipe_resource *new_resource[This->num_back_buffers];
8037ec681f3Smrg        D3DWindowBuffer *new_handles[This->num_back_buffers];
8047ec681f3Smrg        for (i = 0; i < This->num_back_buffers; i++) {
8057ec681f3Smrg            /* Note: if (!new_handles[i]), new_resource[i]
8067ec681f3Smrg             * gets released and contains NULL */
8077ec681f3Smrg            create_present_buffer(This, target_width, target_height, &new_resource[i], &new_handles[i]);
8087ec681f3Smrg            if (!new_handles[i])
8097ec681f3Smrg                failure = true;
8107ec681f3Smrg        }
8117ec681f3Smrg        if (failure) {
8127ec681f3Smrg            for (i = 0; i < This->num_back_buffers; i++) {
8137ec681f3Smrg                if (new_resource[i])
8147ec681f3Smrg                    pipe_resource_reference(&new_resource[i], NULL);
8157ec681f3Smrg                if (new_handles[i])
8167ec681f3Smrg                    D3DWindowBuffer_release(This, new_handles[i]);
8177ec681f3Smrg            }
8187ec681f3Smrg        } else {
8197ec681f3Smrg            for (i = 0; i < This->num_back_buffers; i++) {
8207ec681f3Smrg                D3DWindowBuffer_release(This, This->present_handles[i]);
8217ec681f3Smrg                This->present_handles[i] = new_handles[i];
8227ec681f3Smrg                pipe_resource_reference(&This->present_buffers[i], new_resource[i]);
8237ec681f3Smrg                pipe_resource_reference(&new_resource[i], NULL);
8247ec681f3Smrg            }
8257ec681f3Smrg        }
8267ec681f3Smrg    }
8277ec681f3Smrg
8287ec681f3Smrg    pipe = NineDevice9_GetPipe(This->base.device);
8297ec681f3Smrg
8307ec681f3Smrg    if (This->present_buffers[0]) {
8317ec681f3Smrg        memset(&blit, 0, sizeof(blit));
8327ec681f3Smrg        blit.src.resource = resource;
8337ec681f3Smrg        blit.src.level = 0; /* Note: This->buffers[0]->level should always be 0 */
8347ec681f3Smrg        blit.src.format = resource->format;
8357ec681f3Smrg        blit.src.box.z = 0;
8367ec681f3Smrg        blit.src.box.depth = 1;
8377ec681f3Smrg        blit.src.box.x = 0;
8387ec681f3Smrg        blit.src.box.y = 0;
8397ec681f3Smrg        blit.src.box.width = resource->width0;
8407ec681f3Smrg        blit.src.box.height = resource->height0;
8417ec681f3Smrg
8427ec681f3Smrg        /* Reallocate a new presentation buffer if the target window
8437ec681f3Smrg         * size has changed */
8447ec681f3Smrg        if (target_width != This->present_buffers[0]->width0 ||
8457ec681f3Smrg            target_height != This->present_buffers[0]->height0) {
8467ec681f3Smrg            struct pipe_resource *new_resource;
8477ec681f3Smrg            D3DWindowBuffer *new_handle;
8487ec681f3Smrg
8497ec681f3Smrg            create_present_buffer(This, target_width, target_height, &new_resource, &new_handle);
8507ec681f3Smrg            /* Switch to the new buffer */
8517ec681f3Smrg            if (new_handle) {
8527ec681f3Smrg                D3DWindowBuffer_release(This, This->present_handles[0]);
8537ec681f3Smrg                This->present_handles[0] = new_handle;
8547ec681f3Smrg                pipe_resource_reference(&This->present_buffers[0], new_resource);
8557ec681f3Smrg                pipe_resource_reference(&new_resource, NULL);
8567ec681f3Smrg            }
8577ec681f3Smrg        }
8587ec681f3Smrg
8597ec681f3Smrg        resource = This->present_buffers[0];
8607ec681f3Smrg
8617ec681f3Smrg        blit.dst.resource = resource;
8627ec681f3Smrg        blit.dst.level = 0;
8637ec681f3Smrg        blit.dst.format = resource->format;
8647ec681f3Smrg        blit.dst.box.z = 0;
8657ec681f3Smrg        blit.dst.box.depth = 1;
8667ec681f3Smrg        blit.dst.box.x = 0;
8677ec681f3Smrg        blit.dst.box.y = 0;
8687ec681f3Smrg        blit.dst.box.width = resource->width0;
8697ec681f3Smrg        blit.dst.box.height = resource->height0;
8707ec681f3Smrg
8717ec681f3Smrg        blit.mask = PIPE_MASK_RGBA;
8727ec681f3Smrg        blit.filter = (blit.dst.box.width == blit.src.box.width &&
8737ec681f3Smrg                       blit.dst.box.height == blit.src.box.height) ?
8747ec681f3Smrg                          PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR;
8757ec681f3Smrg        blit.scissor_enable = FALSE;
8767ec681f3Smrg        blit.alpha_blend = FALSE;
8777ec681f3Smrg
8787ec681f3Smrg        pipe->blit(pipe, &blit);
8797ec681f3Smrg    }
8807ec681f3Smrg
8817ec681f3Smrg    /* The resource we present has to resolve fast clears
8827ec681f3Smrg     * if needed (and other things) */
8837ec681f3Smrg    pipe->flush_resource(pipe, resource);
8847ec681f3Smrg
8857ec681f3Smrg    if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
8867ec681f3Smrg        handle_draw_cursor_and_hud(This, resource);
8877ec681f3Smrg
8887ec681f3Smrg    fence = NULL;
8897ec681f3Smrg    /* When threadpool is enabled, we don't submit before the fence
8907ec681f3Smrg     * tells us rendering was finished, thus we can flush async there */
8917ec681f3Smrg    pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME | (This->enable_threadpool ? PIPE_FLUSH_ASYNC : 0));
8927ec681f3Smrg
8937ec681f3Smrg    /* Present now for thread_submit, because we have the fence.
8947ec681f3Smrg     * It's possible we return WASSTILLDRAWING and still Present,
8957ec681f3Smrg     * but it should be fine. */
8967ec681f3Smrg    if (This->enable_threadpool)
8977ec681f3Smrg        pend_present(This, fence, hDestWindowOverride);
8987ec681f3Smrg    if (fence) {
8997ec681f3Smrg        swap_fences_push_back(This, fence);
9007ec681f3Smrg        This->screen->fence_reference(This->screen, &fence, NULL);
9017ec681f3Smrg    }
9027ec681f3Smrg
9037ec681f3Smrg    This->rendering_done = TRUE;
9047ec681f3Smrgbypass_rendering:
9057ec681f3Smrg
9067ec681f3Smrg    if (dwFlags & D3DPRESENT_DONOTWAIT) {
9077ec681f3Smrg        UNTESTED(2);
9087ec681f3Smrg        BOOL still_draw = FALSE;
9097ec681f3Smrg        fence = swap_fences_see_front(This);
9107ec681f3Smrg        if (fence) {
9117ec681f3Smrg            still_draw = !This->screen->fence_finish(This->screen, NULL, fence, 0);
9127ec681f3Smrg            This->screen->fence_reference(This->screen, &fence, NULL);
9137ec681f3Smrg        }
9147ec681f3Smrg        if (still_draw)
9157ec681f3Smrg            return D3DERR_WASSTILLDRAWING;
9167ec681f3Smrg    }
9177ec681f3Smrg
9187ec681f3Smrg    /* Throttle rendering if needed */
9197ec681f3Smrg    fence = swap_fences_pop_front(This);
9207ec681f3Smrg    if (fence) {
9217ec681f3Smrg        (void) This->screen->fence_finish(This->screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
9227ec681f3Smrg        This->screen->fence_reference(This->screen, &fence, NULL);
9237ec681f3Smrg    }
9247ec681f3Smrg
9257ec681f3Smrg    This->rendering_done = FALSE;
9267ec681f3Smrg
9277ec681f3Smrg    if (!This->enable_threadpool) {
9287ec681f3Smrg        This->tasks[0]=NULL;
9297ec681f3Smrg
9307ec681f3Smrg        hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect ? &dest_rect : NULL, NULL, dwFlags);
9317ec681f3Smrg
9327ec681f3Smrg        if (FAILED(hr)) { UNTESTED(3);return hr; }
9337ec681f3Smrg    }
9347ec681f3Smrg
9357ec681f3Smrg    This->base.device->end_scene_since_present = 0;
9367ec681f3Smrg    This->base.device->frame_count++;
9377ec681f3Smrg    return D3D_OK;
9387ec681f3Smrg}
9397ec681f3Smrg
9407ec681f3SmrgHRESULT NINE_WINAPI
9417ec681f3SmrgNineSwapChain9_Present( struct NineSwapChain9 *This,
9427ec681f3Smrg                        const RECT *pSourceRect,
9437ec681f3Smrg                        const RECT *pDestRect,
9447ec681f3Smrg                        HWND hDestWindowOverride,
9457ec681f3Smrg                        const RGNDATA *pDirtyRegion,
9467ec681f3Smrg                        DWORD dwFlags )
9477ec681f3Smrg{
9487ec681f3Smrg    struct pipe_resource *res = NULL;
9497ec681f3Smrg    D3DWindowBuffer *handle_temp;
9507ec681f3Smrg    struct threadpool_task *task_temp;
9517ec681f3Smrg    BOOL *pending_presentation_temp;
9527ec681f3Smrg    int i;
9537ec681f3Smrg    HRESULT hr;
9547ec681f3Smrg
9557ec681f3Smrg    DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
9567ec681f3Smrg        "pDirtyRegion=%p dwFlags=%d\n",
9577ec681f3Smrg        This, pSourceRect, pDestRect, hDestWindowOverride,
9587ec681f3Smrg        pDirtyRegion,dwFlags);
9597ec681f3Smrg
9607ec681f3Smrg    if (This->base.device->ex) {
9617ec681f3Smrg        if (NineSwapChain9_GetOccluded(This)) {
9627ec681f3Smrg            DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n");
9637ec681f3Smrg            return S_PRESENT_OCCLUDED;
9647ec681f3Smrg        }
9657ec681f3Smrg    } else {
9667ec681f3Smrg        if (NineSwapChain9_GetOccluded(This) ||
9677ec681f3Smrg            NineSwapChain9_ResolutionMismatch(This)) {
9687ec681f3Smrg            This->base.device->device_needs_reset = TRUE;
9697ec681f3Smrg        }
9707ec681f3Smrg        if (This->base.device->device_needs_reset) {
9717ec681f3Smrg            DBG("Device is lost. Returning D3DERR_DEVICELOST.\n");
9727ec681f3Smrg            return D3DERR_DEVICELOST;
9737ec681f3Smrg        }
9747ec681f3Smrg    }
9757ec681f3Smrg
9767ec681f3Smrg    nine_csmt_process(This->base.device);
9777ec681f3Smrg
9787ec681f3Smrg    hr = present(This, pSourceRect, pDestRect,
9797ec681f3Smrg                 hDestWindowOverride, pDirtyRegion, dwFlags);
9807ec681f3Smrg    if (hr == D3DERR_WASSTILLDRAWING)
9817ec681f3Smrg        return hr;
9827ec681f3Smrg
9837ec681f3Smrg    if (This->base.device->minor_version_num > 2 &&
9847ec681f3Smrg        This->actx->discard_delayed_release &&
9857ec681f3Smrg        This->params.SwapEffect == D3DSWAPEFFECT_DISCARD &&
9867ec681f3Smrg        This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
9877ec681f3Smrg        int next_buffer = -1;
9887ec681f3Smrg
9897ec681f3Smrg        while (next_buffer == -1) {
9907ec681f3Smrg            /* Find a free backbuffer */
9917ec681f3Smrg            for (i = 1; i < This->num_back_buffers; i++) {
9927ec681f3Smrg                if (!p_atomic_read(This->pending_presentation[i]) &&
9937ec681f3Smrg                    ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) {
9947ec681f3Smrg                    DBG("Found buffer released: %d\n", i);
9957ec681f3Smrg                    next_buffer = i;
9967ec681f3Smrg                    break;
9977ec681f3Smrg                }
9987ec681f3Smrg            }
9997ec681f3Smrg            if (next_buffer == -1) {
10007ec681f3Smrg                DBG("Found no buffer released. Waiting for event\n");
10017ec681f3Smrg                ID3DPresent_WaitBufferReleaseEvent(This->present);
10027ec681f3Smrg            }
10037ec681f3Smrg        }
10047ec681f3Smrg
10057ec681f3Smrg        /* Free the task (we already checked it is finished) */
10067ec681f3Smrg        if (This->tasks[next_buffer])
10077ec681f3Smrg            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[next_buffer]));
10087ec681f3Smrg        assert(!*This->pending_presentation[next_buffer] && !This->tasks[next_buffer]);
10097ec681f3Smrg        This->tasks[next_buffer] = This->tasks[0];
10107ec681f3Smrg        This->tasks[0] = NULL;
10117ec681f3Smrg        pending_presentation_temp = This->pending_presentation[next_buffer];
10127ec681f3Smrg        This->pending_presentation[next_buffer] = This->pending_presentation[0];
10137ec681f3Smrg        This->pending_presentation[0] = pending_presentation_temp;
10147ec681f3Smrg
10157ec681f3Smrg        /* Switch with the released buffer */
10167ec681f3Smrg        pipe_resource_reference(&res, This->buffers[0]->base.resource);
10177ec681f3Smrg        NineSurface9_SetResourceResize(
10187ec681f3Smrg            This->buffers[0], This->buffers[next_buffer]->base.resource);
10197ec681f3Smrg        NineSurface9_SetResourceResize(
10207ec681f3Smrg            This->buffers[next_buffer], res);
10217ec681f3Smrg        pipe_resource_reference(&res, NULL);
10227ec681f3Smrg
10237ec681f3Smrg        if (This->present_buffers[0]) {
10247ec681f3Smrg            pipe_resource_reference(&res, This->present_buffers[0]);
10257ec681f3Smrg            pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]);
10267ec681f3Smrg            pipe_resource_reference(&This->present_buffers[next_buffer], res);
10277ec681f3Smrg            pipe_resource_reference(&res, NULL);
10287ec681f3Smrg        }
10297ec681f3Smrg
10307ec681f3Smrg        handle_temp = This->present_handles[0];
10317ec681f3Smrg        This->present_handles[0] = This->present_handles[next_buffer];
10327ec681f3Smrg        This->present_handles[next_buffer] = handle_temp;
10337ec681f3Smrg    } else {
10347ec681f3Smrg        switch (This->params.SwapEffect) {
10357ec681f3Smrg            case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */
10367ec681f3Smrg            case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */
10377ec681f3Smrg            case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */
10387ec681f3Smrg            case D3DSWAPEFFECT_FLIP:
10397ec681f3Smrg                /* rotate the queue */
10407ec681f3Smrg                pipe_resource_reference(&res, This->buffers[0]->base.resource);
10417ec681f3Smrg                for (i = 1; i < This->num_back_buffers; i++) {
10427ec681f3Smrg                    NineSurface9_SetResourceResize(This->buffers[i - 1],
10437ec681f3Smrg                                                   This->buffers[i]->base.resource);
10447ec681f3Smrg                }
10457ec681f3Smrg                NineSurface9_SetResourceResize(
10467ec681f3Smrg                    This->buffers[This->num_back_buffers - 1], res);
10477ec681f3Smrg                pipe_resource_reference(&res, NULL);
10487ec681f3Smrg
10497ec681f3Smrg                if (This->present_buffers[0]) {
10507ec681f3Smrg                    pipe_resource_reference(&res, This->present_buffers[0]);
10517ec681f3Smrg                    for (i = 1; i < This->num_back_buffers; i++)
10527ec681f3Smrg                        pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
10537ec681f3Smrg                    pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res);
10547ec681f3Smrg                    pipe_resource_reference(&res, NULL);
10557ec681f3Smrg                }
10567ec681f3Smrg
10577ec681f3Smrg                handle_temp = This->present_handles[0];
10587ec681f3Smrg                for (i = 1; i < This->num_back_buffers; i++) {
10597ec681f3Smrg                    This->present_handles[i-1] = This->present_handles[i];
10607ec681f3Smrg                }
10617ec681f3Smrg                This->present_handles[This->num_back_buffers - 1] = handle_temp;
10627ec681f3Smrg                task_temp = This->tasks[0];
10637ec681f3Smrg                for (i = 1; i < This->num_back_buffers; i++) {
10647ec681f3Smrg                    This->tasks[i-1] = This->tasks[i];
10657ec681f3Smrg                }
10667ec681f3Smrg                This->tasks[This->num_back_buffers - 1] = task_temp;
10677ec681f3Smrg                pending_presentation_temp = This->pending_presentation[0];
10687ec681f3Smrg                for (i = 1; i < This->num_back_buffers; i++) {
10697ec681f3Smrg                    This->pending_presentation[i-1] = This->pending_presentation[i];
10707ec681f3Smrg                }
10717ec681f3Smrg                This->pending_presentation[This->num_back_buffers - 1] = pending_presentation_temp;
10727ec681f3Smrg                break;
10737ec681f3Smrg
10747ec681f3Smrg            case D3DSWAPEFFECT_COPY:
10757ec681f3Smrg                /* do nothing */
10767ec681f3Smrg                break;
10777ec681f3Smrg        }
10787ec681f3Smrg
10797ec681f3Smrg        if (This->tasks[0])
10807ec681f3Smrg            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
10817ec681f3Smrg        assert(!*This->pending_presentation[0]);
10827ec681f3Smrg
10837ec681f3Smrg        ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
10847ec681f3Smrg    }
10857ec681f3Smrg
10867ec681f3Smrg    This->base.device->context.changed.group |= NINE_STATE_FB;
10877ec681f3Smrg
10887ec681f3Smrg    return hr;
10897ec681f3Smrg}
10907ec681f3Smrg
10917ec681f3SmrgHRESULT NINE_WINAPI
10927ec681f3SmrgNineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
10937ec681f3Smrg                                   IDirect3DSurface9 *pDestSurface )
10947ec681f3Smrg{
10957ec681f3Smrg    struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
10967ec681f3Smrg    struct NineDevice9 *pDevice = This->base.device;
10977ec681f3Smrg    unsigned int width, height;
10987ec681f3Smrg    struct pipe_resource *temp_resource;
10997ec681f3Smrg    struct NineSurface9 *temp_surface;
11007ec681f3Smrg    D3DWindowBuffer *temp_handle;
11017ec681f3Smrg    D3DSURFACE_DESC desc;
11027ec681f3Smrg    HRESULT hr;
11037ec681f3Smrg
11047ec681f3Smrg    DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
11057ec681f3Smrg        This, pDestSurface);
11067ec681f3Smrg
11077ec681f3Smrg    user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
11087ec681f3Smrg
11097ec681f3Smrg    width = dest_surface->desc.Width;
11107ec681f3Smrg    height = dest_surface->desc.Height;
11117ec681f3Smrg
11127ec681f3Smrg    /* Note: front window size and destination size are supposed
11137ec681f3Smrg     * to match. However it's not very clear what should get taken in Windowed
11147ec681f3Smrg     * mode. It may need a fix */
11157ec681f3Smrg    create_present_buffer(This, width, height, &temp_resource, &temp_handle);
11167ec681f3Smrg
11177ec681f3Smrg    if (!temp_resource || !temp_handle) {
11187ec681f3Smrg        return D3DERR_INVALIDCALL;
11197ec681f3Smrg    }
11207ec681f3Smrg
11217ec681f3Smrg    desc.Type = D3DRTYPE_SURFACE;
11227ec681f3Smrg    desc.Pool = D3DPOOL_DEFAULT;
11237ec681f3Smrg    desc.MultiSampleType = D3DMULTISAMPLE_NONE;
11247ec681f3Smrg    desc.MultiSampleQuality = 0;
11257ec681f3Smrg    desc.Width = width;
11267ec681f3Smrg    desc.Height = height;
11277ec681f3Smrg    /* NineSurface9_CopyDefaultToMem needs same format. */
11287ec681f3Smrg    desc.Format = dest_surface->desc.Format;
11297ec681f3Smrg    desc.Usage = D3DUSAGE_RENDERTARGET;
11307ec681f3Smrg    hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0,
11317ec681f3Smrg                          0, 0, &desc, &temp_surface);
11327ec681f3Smrg    pipe_resource_reference(&temp_resource, NULL);
11337ec681f3Smrg    if (FAILED(hr)) {
11347ec681f3Smrg        DBG("Failed to create temp FrontBuffer surface.\n");
11357ec681f3Smrg        return hr;
11367ec681f3Smrg    }
11377ec681f3Smrg
11387ec681f3Smrg    ID3DPresent_FrontBufferCopy(This->present, temp_handle);
11397ec681f3Smrg
11407ec681f3Smrg    NineSurface9_CopyDefaultToMem(dest_surface, temp_surface);
11417ec681f3Smrg
11427ec681f3Smrg    ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
11437ec681f3Smrg    NineUnknown_Destroy(NineUnknown(temp_surface));
11447ec681f3Smrg
11457ec681f3Smrg    return D3D_OK;
11467ec681f3Smrg}
11477ec681f3Smrg
11487ec681f3SmrgHRESULT NINE_WINAPI
11497ec681f3SmrgNineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
11507ec681f3Smrg                              UINT iBackBuffer,
11517ec681f3Smrg                              D3DBACKBUFFER_TYPE Type,
11527ec681f3Smrg                              IDirect3DSurface9 **ppBackBuffer )
11537ec681f3Smrg{
11547ec681f3Smrg    DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
11557ec681f3Smrg        This, iBackBuffer, Type, ppBackBuffer);
11567ec681f3Smrg    (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
11577ec681f3Smrg    /* don't touch ppBackBuffer on error */
11587ec681f3Smrg    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
11597ec681f3Smrg    user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
11607ec681f3Smrg
11617ec681f3Smrg    NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
11627ec681f3Smrg    *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
11637ec681f3Smrg    return D3D_OK;
11647ec681f3Smrg}
11657ec681f3Smrg
11667ec681f3SmrgHRESULT NINE_WINAPI
11677ec681f3SmrgNineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
11687ec681f3Smrg                                D3DRASTER_STATUS *pRasterStatus )
11697ec681f3Smrg{
11707ec681f3Smrg    DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
11717ec681f3Smrg        This, pRasterStatus);
11727ec681f3Smrg    user_assert(pRasterStatus != NULL, E_POINTER);
11737ec681f3Smrg    return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
11747ec681f3Smrg}
11757ec681f3Smrg
11767ec681f3SmrgHRESULT NINE_WINAPI
11777ec681f3SmrgNineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
11787ec681f3Smrg                               D3DDISPLAYMODE *pMode )
11797ec681f3Smrg{
11807ec681f3Smrg    D3DDISPLAYMODEEX mode;
11817ec681f3Smrg    D3DDISPLAYROTATION rot;
11827ec681f3Smrg    HRESULT hr;
11837ec681f3Smrg
11847ec681f3Smrg    DBG("GetDisplayMode: This=%p pMode=%p\n",
11857ec681f3Smrg        This, pMode);
11867ec681f3Smrg    user_assert(pMode != NULL, E_POINTER);
11877ec681f3Smrg
11887ec681f3Smrg    hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
11897ec681f3Smrg    if (SUCCEEDED(hr)) {
11907ec681f3Smrg        pMode->Width = mode.Width;
11917ec681f3Smrg        pMode->Height = mode.Height;
11927ec681f3Smrg        pMode->RefreshRate = mode.RefreshRate;
11937ec681f3Smrg        pMode->Format = mode.Format;
11947ec681f3Smrg    }
11957ec681f3Smrg    return hr;
11967ec681f3Smrg}
11977ec681f3Smrg
11987ec681f3SmrgHRESULT NINE_WINAPI
11997ec681f3SmrgNineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
12007ec681f3Smrg                                     D3DPRESENT_PARAMETERS *pPresentationParameters )
12017ec681f3Smrg{
12027ec681f3Smrg    DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
12037ec681f3Smrg        This, pPresentationParameters);
12047ec681f3Smrg    user_assert(pPresentationParameters != NULL, E_POINTER);
12057ec681f3Smrg    *pPresentationParameters = This->params;
12067ec681f3Smrg    return D3D_OK;
12077ec681f3Smrg}
12087ec681f3Smrg
12097ec681f3SmrgIDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
12107ec681f3Smrg    (void *)NineUnknown_QueryInterface,
12117ec681f3Smrg    (void *)NineUnknown_AddRef,
12127ec681f3Smrg    (void *)NineUnknown_Release,
12137ec681f3Smrg    (void *)NineSwapChain9_Present,
12147ec681f3Smrg    (void *)NineSwapChain9_GetFrontBufferData,
12157ec681f3Smrg    (void *)NineSwapChain9_GetBackBuffer,
12167ec681f3Smrg    (void *)NineSwapChain9_GetRasterStatus,
12177ec681f3Smrg    (void *)NineSwapChain9_GetDisplayMode,
12187ec681f3Smrg    (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
12197ec681f3Smrg    (void *)NineSwapChain9_GetPresentParameters
12207ec681f3Smrg};
12217ec681f3Smrg
12227ec681f3Smrgstatic const GUID *NineSwapChain9_IIDs[] = {
12237ec681f3Smrg    &IID_IDirect3DSwapChain9,
12247ec681f3Smrg    &IID_IUnknown,
12257ec681f3Smrg    NULL
12267ec681f3Smrg};
12277ec681f3Smrg
12287ec681f3SmrgHRESULT
12297ec681f3SmrgNineSwapChain9_new( struct NineDevice9 *pDevice,
12307ec681f3Smrg                    BOOL implicit,
12317ec681f3Smrg                    ID3DPresent *pPresent,
12327ec681f3Smrg                    D3DPRESENT_PARAMETERS *pPresentationParameters,
12337ec681f3Smrg                    struct d3dadapter9_context *pCTX,
12347ec681f3Smrg                    HWND hFocusWindow,
12357ec681f3Smrg                    struct NineSwapChain9 **ppOut )
12367ec681f3Smrg{
12377ec681f3Smrg    NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
12387ec681f3Smrg                          implicit, pPresent, pPresentationParameters,
12397ec681f3Smrg                          pCTX, hFocusWindow, NULL);
12407ec681f3Smrg}
12417ec681f3Smrg
12427ec681f3SmrgBOOL
12437ec681f3SmrgNineSwapChain9_GetOccluded( struct NineSwapChain9 *This )
12447ec681f3Smrg{
12457ec681f3Smrg    if (This->base.device->minor_version_num > 0) {
12467ec681f3Smrg        return ID3DPresent_GetWindowOccluded(This->present);
12477ec681f3Smrg    }
12487ec681f3Smrg
12497ec681f3Smrg    return FALSE;
12507ec681f3Smrg}
12517ec681f3Smrg
12527ec681f3SmrgBOOL
12537ec681f3SmrgNineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This )
12547ec681f3Smrg{
12557ec681f3Smrg    if (This->base.device->minor_version_num > 1) {
12567ec681f3Smrg        return ID3DPresent_ResolutionMismatch(This->present);
12577ec681f3Smrg    }
12587ec681f3Smrg
12597ec681f3Smrg    return FALSE;
12607ec681f3Smrg}
12617ec681f3Smrg
12627ec681f3SmrgHANDLE
12637ec681f3SmrgNineSwapChain9_CreateThread( struct NineSwapChain9 *This,
12647ec681f3Smrg                                 void *pFuncAddress,
12657ec681f3Smrg                                 void *pParam )
12667ec681f3Smrg{
12677ec681f3Smrg    if (This->base.device->minor_version_num > 1) {
12687ec681f3Smrg        return ID3DPresent_CreateThread(This->present, pFuncAddress, pParam);
12697ec681f3Smrg    }
12707ec681f3Smrg
12717ec681f3Smrg    return NULL;
12727ec681f3Smrg}
12737ec681f3Smrg
12747ec681f3Smrgvoid
12757ec681f3SmrgNineSwapChain9_WaitForThread( struct NineSwapChain9 *This,
12767ec681f3Smrg                                  HANDLE thread )
12777ec681f3Smrg{
12787ec681f3Smrg    if (This->base.device->minor_version_num > 1) {
12797ec681f3Smrg        (void) ID3DPresent_WaitForThread(This->present, thread);
12807ec681f3Smrg    }
12817ec681f3Smrg}
12827ec681f3Smrg
12837ec681f3Smrgstatic int
12847ec681f3SmrgNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
12857ec681f3Smrg                                            D3DPRESENT_PARAMETERS *pParams )
12867ec681f3Smrg{
12877ec681f3Smrg    int count = pParams->BackBufferCount;
12887ec681f3Smrg
12897ec681f3Smrg    /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
12907ec681f3Smrg     * Here we don't get back the initial content of the screen. To emulate the behaviour
12917ec681f3Smrg     * we allocate an additional buffer */
12927ec681f3Smrg    if (pParams->SwapEffect != D3DSWAPEFFECT_COPY)
12937ec681f3Smrg        count++;
12947ec681f3Smrg    /* With DISCARD, as there is no guarantee about the buffer contents, we can use
12957ec681f3Smrg     * an arbitrary number of buffers */
12967ec681f3Smrg    if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) {
12977ec681f3Smrg        /* thread_submit's can have maximum count or This->actx->throttling_value + 1
12987ec681f3Smrg         * frames in flight being rendered and not shown.
12997ec681f3Smrg         * Do not let count decrease that number */
13007ec681f3Smrg        if (This->actx->thread_submit && count < This->desired_fences)
13017ec681f3Smrg            count = This->desired_fences;
13027ec681f3Smrg        /* When we enable AllowDISCARDDelayedRelease, we must ensure
13037ec681f3Smrg         * to have at least 4 buffers to meet INTERVAL_IMMEDIATE,
13047ec681f3Smrg         * since the display server/compositor can hold 3 buffers
13057ec681f3Smrg         * without releasing them:
13067ec681f3Smrg         * . Buffer on screen.
13077ec681f3Smrg         * . Buffer scheduled kernel side to be next on screen.
13087ec681f3Smrg         * . Last buffer sent. */
13097ec681f3Smrg        if (This->base.device->minor_version_num > 2 &&
13107ec681f3Smrg            This->actx->discard_delayed_release &&
13117ec681f3Smrg            pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
13127ec681f3Smrg            if (This->actx->thread_submit && count < 4)
13137ec681f3Smrg                count = 4;
13147ec681f3Smrg            /* When thread_submit is not used, 5 buffers are actually needed,
13157ec681f3Smrg             * because in case a pageflip is missed because rendering wasn't finished,
13167ec681f3Smrg             * the Xserver will hold 4 buffers. */
13177ec681f3Smrg            else if (!This->actx->thread_submit && count < 5)
13187ec681f3Smrg                count = 5;
13197ec681f3Smrg            /* Somehow this cases needs 5 with thread_submit, or else you get a small performance hit */
13207ec681f3Smrg            if (This->actx->tearfree_discard && count < 5)
13217ec681f3Smrg                count = 5;
13227ec681f3Smrg        }
13237ec681f3Smrg    }
13247ec681f3Smrg
13257ec681f3Smrg    return count;
13267ec681f3Smrg}
1327