1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub
8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom
9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci#include "swapchain9.h"
24bf215546Sopenharmony_ci#include "surface9.h"
25bf215546Sopenharmony_ci#include "device9.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "nine_helpers.h"
28bf215546Sopenharmony_ci#include "nine_pipe.h"
29bf215546Sopenharmony_ci#include "nine_dump.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "util/u_atomic.h"
32bf215546Sopenharmony_ci#include "util/u_inlines.h"
33bf215546Sopenharmony_ci#include "util/u_surface.h"
34bf215546Sopenharmony_ci#include "hud/hud_context.h"
35bf215546Sopenharmony_ci#include "frontend/drm_driver.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "threadpool.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#define DBG_CHANNEL DBG_SWAPCHAIN
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ciHRESULT
44bf215546Sopenharmony_ciNineSwapChain9_ctor( struct NineSwapChain9 *This,
45bf215546Sopenharmony_ci                     struct NineUnknownParams *pParams,
46bf215546Sopenharmony_ci                     BOOL implicit,
47bf215546Sopenharmony_ci                     ID3DPresent *pPresent,
48bf215546Sopenharmony_ci                     D3DPRESENT_PARAMETERS *pPresentationParameters,
49bf215546Sopenharmony_ci                     struct d3dadapter9_context *pCTX,
50bf215546Sopenharmony_ci                     HWND hFocusWindow,
51bf215546Sopenharmony_ci                     D3DDISPLAYMODEEX *mode )
52bf215546Sopenharmony_ci{
53bf215546Sopenharmony_ci    HRESULT hr;
54bf215546Sopenharmony_ci    int i;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci    DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
57bf215546Sopenharmony_ci        This, pParams->device, pPresent, pCTX, hFocusWindow);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci    hr = NineUnknown_ctor(&This->base, pParams);
60bf215546Sopenharmony_ci    if (FAILED(hr))
61bf215546Sopenharmony_ci        return hr;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci    This->screen = NineDevice9_GetScreen(This->base.device);
64bf215546Sopenharmony_ci    This->implicit = implicit;
65bf215546Sopenharmony_ci    This->actx = pCTX;
66bf215546Sopenharmony_ci    This->present = pPresent;
67bf215546Sopenharmony_ci    This->mode = NULL;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci    ID3DPresent_AddRef(pPresent);
70bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 2) {
71bf215546Sopenharmony_ci        D3DPRESENT_PARAMETERS2 params2;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci        memset(&params2, 0, sizeof(D3DPRESENT_PARAMETERS2));
74bf215546Sopenharmony_ci        params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release;
75bf215546Sopenharmony_ci        params2.TearFreeDISCARD = This->actx->tearfree_discard;
76bf215546Sopenharmony_ci        ID3DPresent_SetPresentParameters2(pPresent, &params2);
77bf215546Sopenharmony_ci    }
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci    if (!pPresentationParameters->hDeviceWindow)
80bf215546Sopenharmony_ci        pPresentationParameters->hDeviceWindow = hFocusWindow;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci    This->rendering_done = FALSE;
83bf215546Sopenharmony_ci    This->pool = NULL;
84bf215546Sopenharmony_ci    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
85bf215546Sopenharmony_ci        This->pending_presentation[i] = calloc(1, sizeof(BOOL));
86bf215546Sopenharmony_ci        if (!This->pending_presentation[i])
87bf215546Sopenharmony_ci            return E_OUTOFMEMORY;
88bf215546Sopenharmony_ci    }
89bf215546Sopenharmony_ci    return NineSwapChain9_Resize(This, pPresentationParameters, mode);
90bf215546Sopenharmony_ci}
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic D3DWindowBuffer *
93bf215546Sopenharmony_ciD3DWindowBuffer_create(struct NineSwapChain9 *This,
94bf215546Sopenharmony_ci                       struct pipe_resource *resource,
95bf215546Sopenharmony_ci                       int depth,
96bf215546Sopenharmony_ci                       int for_frontbuffer_reading)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci    D3DWindowBuffer *ret;
99bf215546Sopenharmony_ci    struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device);
100bf215546Sopenharmony_ci    struct winsys_handle whandle;
101bf215546Sopenharmony_ci    int stride, dmaBufFd;
102bf215546Sopenharmony_ci    HRESULT hr;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci    memset(&whandle, 0, sizeof(whandle));
105bf215546Sopenharmony_ci    whandle.type = WINSYS_HANDLE_TYPE_FD;
106bf215546Sopenharmony_ci    if (!This->screen->resource_get_handle(This->screen, pipe, resource,
107bf215546Sopenharmony_ci                                           &whandle,
108bf215546Sopenharmony_ci                                           for_frontbuffer_reading ?
109bf215546Sopenharmony_ci                                               PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE :
110bf215546Sopenharmony_ci                                               PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) {
111bf215546Sopenharmony_ci        ERR("Failed to get handle for resource\n");
112bf215546Sopenharmony_ci        return NULL;
113bf215546Sopenharmony_ci    }
114bf215546Sopenharmony_ci    nine_context_get_pipe_release(This->base.device);
115bf215546Sopenharmony_ci    stride = whandle.stride;
116bf215546Sopenharmony_ci    dmaBufFd = whandle.handle;
117bf215546Sopenharmony_ci    hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
118bf215546Sopenharmony_ci                                                  dmaBufFd,
119bf215546Sopenharmony_ci                                                  resource->width0,
120bf215546Sopenharmony_ci                                                  resource->height0,
121bf215546Sopenharmony_ci                                                  stride,
122bf215546Sopenharmony_ci                                                  depth,
123bf215546Sopenharmony_ci                                                  32,
124bf215546Sopenharmony_ci                                                  &ret);
125bf215546Sopenharmony_ci    assert (SUCCEEDED(hr));
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci    if (FAILED(hr)) {
128bf215546Sopenharmony_ci        ERR("Failed to create new D3DWindowBufferFromDmaBuf\n");
129bf215546Sopenharmony_ci        return NULL;
130bf215546Sopenharmony_ci    }
131bf215546Sopenharmony_ci    return ret;
132bf215546Sopenharmony_ci}
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_cistatic void
135bf215546Sopenharmony_ciD3DWindowBuffer_release(struct NineSwapChain9 *This,
136bf215546Sopenharmony_ci                        D3DWindowBuffer *present_handle)
137bf215546Sopenharmony_ci{
138bf215546Sopenharmony_ci    int i;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci    /* IsBufferReleased API not available */
141bf215546Sopenharmony_ci    if (This->base.device->minor_version_num <= 2) {
142bf215546Sopenharmony_ci        ID3DPresent_DestroyD3DWindowBuffer(This->present, present_handle);
143bf215546Sopenharmony_ci        return;
144bf215546Sopenharmony_ci    }
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci    /* Add it to the 'pending release' list */
147bf215546Sopenharmony_ci    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
148bf215546Sopenharmony_ci        if (!This->present_handles_pending_release[i]) {
149bf215546Sopenharmony_ci            This->present_handles_pending_release[i] = present_handle;
150bf215546Sopenharmony_ci            break;
151bf215546Sopenharmony_ci        }
152bf215546Sopenharmony_ci    }
153bf215546Sopenharmony_ci    if (i == (D3DPRESENT_BACK_BUFFERS_MAX_EX + 1)) {
154bf215546Sopenharmony_ci        ERR("Server not releasing buffers...\n");
155bf215546Sopenharmony_ci        assert(false);
156bf215546Sopenharmony_ci    }
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci    /* Destroy elements of the list released by the server */
159bf215546Sopenharmony_ci    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
160bf215546Sopenharmony_ci        if (This->present_handles_pending_release[i] &&
161bf215546Sopenharmony_ci            ID3DPresent_IsBufferReleased(This->present, This->present_handles_pending_release[i])) {
162bf215546Sopenharmony_ci            /* WaitBufferReleased also waits the presentation feedback
163bf215546Sopenharmony_ci             * (which should arrive at about the same time),
164bf215546Sopenharmony_ci             * while IsBufferReleased doesn't. DestroyD3DWindowBuffer unfortunately
165bf215546Sopenharmony_ci             * checks it to release immediately all data, else the release
166bf215546Sopenharmony_ci             * is postponed for This->present release. To avoid leaks (we may handle
167bf215546Sopenharmony_ci             * a lot of resize), call WaitBufferReleased. */
168bf215546Sopenharmony_ci            ID3DPresent_WaitBufferReleased(This->present, This->present_handles_pending_release[i]);
169bf215546Sopenharmony_ci            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]);
170bf215546Sopenharmony_ci            This->present_handles_pending_release[i] = NULL;
171bf215546Sopenharmony_ci        }
172bf215546Sopenharmony_ci    }
173bf215546Sopenharmony_ci}
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_cistatic int
176bf215546Sopenharmony_ciNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
177bf215546Sopenharmony_ci                                            D3DPRESENT_PARAMETERS *pParams );
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ciHRESULT
180bf215546Sopenharmony_ciNineSwapChain9_Resize( struct NineSwapChain9 *This,
181bf215546Sopenharmony_ci                       D3DPRESENT_PARAMETERS *pParams,
182bf215546Sopenharmony_ci                       D3DDISPLAYMODEEX *mode )
183bf215546Sopenharmony_ci{
184bf215546Sopenharmony_ci    struct NineDevice9 *pDevice = This->base.device;
185bf215546Sopenharmony_ci    D3DSURFACE_DESC desc;
186bf215546Sopenharmony_ci    HRESULT hr;
187bf215546Sopenharmony_ci    struct pipe_resource *resource, tmplt;
188bf215546Sopenharmony_ci    enum pipe_format pf;
189bf215546Sopenharmony_ci    BOOL has_present_buffers = FALSE;
190bf215546Sopenharmony_ci    int depth;
191bf215546Sopenharmony_ci    unsigned i, oldBufferCount, newBufferCount;
192bf215546Sopenharmony_ci    D3DMULTISAMPLE_TYPE multisample_type;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci    DBG("This=%p pParams=%p\n", This, pParams);
195bf215546Sopenharmony_ci    user_assert(pParams != NULL, E_POINTER);
196bf215546Sopenharmony_ci    user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL);
197bf215546Sopenharmony_ci    user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) ||
198bf215546Sopenharmony_ci                (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL);
199bf215546Sopenharmony_ci    user_assert(pDevice->ex || pParams->BackBufferCount <=
200bf215546Sopenharmony_ci                D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL);
201bf215546Sopenharmony_ci    user_assert(!pDevice->ex || pParams->BackBufferCount <=
202bf215546Sopenharmony_ci                D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL);
203bf215546Sopenharmony_ci    user_assert(pDevice->ex ||
204bf215546Sopenharmony_ci                (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) ||
205bf215546Sopenharmony_ci                (pParams->SwapEffect == D3DSWAPEFFECT_COPY) ||
206bf215546Sopenharmony_ci                (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL);
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci    DBG("pParams(%p):\n"
209bf215546Sopenharmony_ci        "BackBufferWidth: %u\n"
210bf215546Sopenharmony_ci        "BackBufferHeight: %u\n"
211bf215546Sopenharmony_ci        "BackBufferFormat: %s\n"
212bf215546Sopenharmony_ci        "BackBufferCount: %u\n"
213bf215546Sopenharmony_ci        "MultiSampleType: %u\n"
214bf215546Sopenharmony_ci        "MultiSampleQuality: %u\n"
215bf215546Sopenharmony_ci        "SwapEffect: %u\n"
216bf215546Sopenharmony_ci        "hDeviceWindow: %p\n"
217bf215546Sopenharmony_ci        "Windowed: %i\n"
218bf215546Sopenharmony_ci        "EnableAutoDepthStencil: %i\n"
219bf215546Sopenharmony_ci        "AutoDepthStencilFormat: %s\n"
220bf215546Sopenharmony_ci        "Flags: %s\n"
221bf215546Sopenharmony_ci        "FullScreen_RefreshRateInHz: %u\n"
222bf215546Sopenharmony_ci        "PresentationInterval: %x\n", pParams,
223bf215546Sopenharmony_ci        pParams->BackBufferWidth, pParams->BackBufferHeight,
224bf215546Sopenharmony_ci        d3dformat_to_string(pParams->BackBufferFormat),
225bf215546Sopenharmony_ci        pParams->BackBufferCount,
226bf215546Sopenharmony_ci        pParams->MultiSampleType, pParams->MultiSampleQuality,
227bf215546Sopenharmony_ci        pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
228bf215546Sopenharmony_ci        pParams->EnableAutoDepthStencil,
229bf215546Sopenharmony_ci        d3dformat_to_string(pParams->AutoDepthStencilFormat),
230bf215546Sopenharmony_ci        nine_D3DPRESENTFLAG_to_str(pParams->Flags),
231bf215546Sopenharmony_ci        pParams->FullScreen_RefreshRateInHz,
232bf215546Sopenharmony_ci        pParams->PresentationInterval);
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci    if (pParams->BackBufferCount == 0) {
235bf215546Sopenharmony_ci        pParams->BackBufferCount = 1;
236bf215546Sopenharmony_ci    }
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci    if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
239bf215546Sopenharmony_ci        pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
240bf215546Sopenharmony_ci    }
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci    This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
243bf215546Sopenharmony_ci    /* +1 because we add the fence of the current buffer before popping an old one */
244bf215546Sopenharmony_ci    if (This->desired_fences > DRI_SWAP_FENCES_MAX)
245bf215546Sopenharmony_ci        This->desired_fences = DRI_SWAP_FENCES_MAX;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci    if (This->actx->vblank_mode == 0)
248bf215546Sopenharmony_ci        pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
249bf215546Sopenharmony_ci    else if (This->actx->vblank_mode == 3)
250bf215546Sopenharmony_ci        pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci    if (mode && This->mode) {
253bf215546Sopenharmony_ci        *(This->mode) = *mode;
254bf215546Sopenharmony_ci    } else if (mode) {
255bf215546Sopenharmony_ci        This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
256bf215546Sopenharmony_ci        memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
257bf215546Sopenharmony_ci    } else {
258bf215546Sopenharmony_ci        free(This->mode);
259bf215546Sopenharmony_ci        This->mode = NULL;
260bf215546Sopenharmony_ci    }
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci    /* Note: It is the role of the backend to fill if necessary
263bf215546Sopenharmony_ci     * BackBufferWidth and BackBufferHeight */
264bf215546Sopenharmony_ci    hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
265bf215546Sopenharmony_ci    if (hr != D3D_OK)
266bf215546Sopenharmony_ci        return hr;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci    oldBufferCount = This->num_back_buffers;
269bf215546Sopenharmony_ci    newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci    multisample_type = pParams->MultiSampleType;
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci    /* Map MultiSampleQuality to MultiSampleType */
274bf215546Sopenharmony_ci    hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat,
275bf215546Sopenharmony_ci                                   &multisample_type,
276bf215546Sopenharmony_ci                                   pParams->MultiSampleQuality,
277bf215546Sopenharmony_ci                                   NULL);
278bf215546Sopenharmony_ci    if (FAILED(hr)) {
279bf215546Sopenharmony_ci        return hr;
280bf215546Sopenharmony_ci    }
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci    pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat,
283bf215546Sopenharmony_ci                                     PIPE_TEXTURE_2D, multisample_type,
284bf215546Sopenharmony_ci                                     PIPE_BIND_RENDER_TARGET, FALSE, FALSE);
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci    if (This->actx->linear_framebuffer ||
287bf215546Sopenharmony_ci        (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
288bf215546Sopenharmony_ci        pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
289bf215546Sopenharmony_ci        pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
290bf215546Sopenharmony_ci        multisample_type >= 2 ||
291bf215546Sopenharmony_ci        (This->actx->ref && This->actx->ref == This->screen))
292bf215546Sopenharmony_ci        has_present_buffers = TRUE;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci    /* Note: the buffer depth has to match the window depth.
295bf215546Sopenharmony_ci     * In practice, ARGB buffers can be used with windows
296bf215546Sopenharmony_ci     * of depth 24. Windows of depth 32 are extremely rare.
297bf215546Sopenharmony_ci     * So even if the buffer is ARGB, say it is depth 24.
298bf215546Sopenharmony_ci     * It is common practice, for example that's how
299bf215546Sopenharmony_ci     * glamor implements depth 24.
300bf215546Sopenharmony_ci     * TODO: handle windows with other depths. Not possible in the short term.
301bf215546Sopenharmony_ci     * For example 16 bits.*/
302bf215546Sopenharmony_ci    depth = 24;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci    memset(&tmplt, 0, sizeof(tmplt));
305bf215546Sopenharmony_ci    tmplt.target = PIPE_TEXTURE_2D;
306bf215546Sopenharmony_ci    tmplt.width0 = pParams->BackBufferWidth;
307bf215546Sopenharmony_ci    tmplt.height0 = pParams->BackBufferHeight;
308bf215546Sopenharmony_ci    tmplt.depth0 = 1;
309bf215546Sopenharmony_ci    tmplt.last_level = 0;
310bf215546Sopenharmony_ci    tmplt.array_size = 1;
311bf215546Sopenharmony_ci    tmplt.usage = PIPE_USAGE_DEFAULT;
312bf215546Sopenharmony_ci    tmplt.flags = 0;
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci    desc.Type = D3DRTYPE_SURFACE;
315bf215546Sopenharmony_ci    desc.Pool = D3DPOOL_DEFAULT;
316bf215546Sopenharmony_ci    desc.MultiSampleType = pParams->MultiSampleType;
317bf215546Sopenharmony_ci    desc.MultiSampleQuality = pParams->MultiSampleQuality;
318bf215546Sopenharmony_ci    desc.Width = pParams->BackBufferWidth;
319bf215546Sopenharmony_ci    desc.Height = pParams->BackBufferHeight;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci    for (i = 0; i < oldBufferCount; i++) {
322bf215546Sopenharmony_ci        if (This->tasks[i])
323bf215546Sopenharmony_ci            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i]));
324bf215546Sopenharmony_ci    }
325bf215546Sopenharmony_ci    memset(This->tasks, 0, sizeof(This->tasks));
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci    if (This->pool) {
328bf215546Sopenharmony_ci        _mesa_threadpool_destroy(This, This->pool);
329bf215546Sopenharmony_ci        This->pool = NULL;
330bf215546Sopenharmony_ci    }
331bf215546Sopenharmony_ci    This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
332bf215546Sopenharmony_ci    if (This->enable_threadpool)
333bf215546Sopenharmony_ci        This->pool = _mesa_threadpool_create(This);
334bf215546Sopenharmony_ci    if (!This->pool)
335bf215546Sopenharmony_ci        This->enable_threadpool = FALSE;
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci    for (i = 0; i < oldBufferCount; i++) {
338bf215546Sopenharmony_ci        D3DWindowBuffer_release(This, This->present_handles[i]);
339bf215546Sopenharmony_ci        This->present_handles[i] = NULL;
340bf215546Sopenharmony_ci        if (This->present_buffers[i])
341bf215546Sopenharmony_ci            pipe_resource_reference(&(This->present_buffers[i]), NULL);
342bf215546Sopenharmony_ci    }
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci    if (newBufferCount != oldBufferCount) {
345bf215546Sopenharmony_ci        for (i = newBufferCount; i < oldBufferCount;
346bf215546Sopenharmony_ci             ++i)
347bf215546Sopenharmony_ci            NineUnknown_Detach(NineUnknown(This->buffers[i]));
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci        for (i = oldBufferCount; i < newBufferCount; ++i) {
350bf215546Sopenharmony_ci            This->buffers[i] = NULL;
351bf215546Sopenharmony_ci            This->present_handles[i] = NULL;
352bf215546Sopenharmony_ci        }
353bf215546Sopenharmony_ci    }
354bf215546Sopenharmony_ci    This->num_back_buffers = newBufferCount;
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci    for (i = 0; i < newBufferCount; ++i) {
357bf215546Sopenharmony_ci        tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
358bf215546Sopenharmony_ci        tmplt.nr_samples = multisample_type;
359bf215546Sopenharmony_ci        tmplt.nr_storage_samples = multisample_type;
360bf215546Sopenharmony_ci        if (!has_present_buffers)
361bf215546Sopenharmony_ci            tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS;
362bf215546Sopenharmony_ci        tmplt.format = d3d9_to_pipe_format_checked(This->screen,
363bf215546Sopenharmony_ci                                                   pParams->BackBufferFormat,
364bf215546Sopenharmony_ci                                                   PIPE_TEXTURE_2D,
365bf215546Sopenharmony_ci                                                   tmplt.nr_samples,
366bf215546Sopenharmony_ci                                                   tmplt.bind, FALSE, FALSE);
367bf215546Sopenharmony_ci        if (tmplt.format == PIPE_FORMAT_NONE)
368bf215546Sopenharmony_ci            return D3DERR_INVALIDCALL;
369bf215546Sopenharmony_ci        resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
370bf215546Sopenharmony_ci        if (!resource) {
371bf215546Sopenharmony_ci            DBG("Failed to create pipe_resource.\n");
372bf215546Sopenharmony_ci            return D3DERR_OUTOFVIDEOMEMORY;
373bf215546Sopenharmony_ci        }
374bf215546Sopenharmony_ci        if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
375bf215546Sopenharmony_ci            resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
376bf215546Sopenharmony_ci        if (This->buffers[i]) {
377bf215546Sopenharmony_ci            NineSurface9_SetMultiSampleType(This->buffers[i], desc.MultiSampleType);
378bf215546Sopenharmony_ci            NineSurface9_SetResourceResize(This->buffers[i], resource);
379bf215546Sopenharmony_ci            if (has_present_buffers)
380bf215546Sopenharmony_ci                pipe_resource_reference(&resource, NULL);
381bf215546Sopenharmony_ci        } else {
382bf215546Sopenharmony_ci            desc.Format = pParams->BackBufferFormat;
383bf215546Sopenharmony_ci            desc.Usage = D3DUSAGE_RENDERTARGET;
384bf215546Sopenharmony_ci            hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0,
385bf215546Sopenharmony_ci                                  0, 0, &desc, &This->buffers[i]);
386bf215546Sopenharmony_ci            if (has_present_buffers)
387bf215546Sopenharmony_ci                pipe_resource_reference(&resource, NULL);
388bf215546Sopenharmony_ci            if (FAILED(hr)) {
389bf215546Sopenharmony_ci                DBG("Failed to create RT surface.\n");
390bf215546Sopenharmony_ci                return hr;
391bf215546Sopenharmony_ci            }
392bf215546Sopenharmony_ci            This->buffers[i]->base.base.forward = FALSE;
393bf215546Sopenharmony_ci        }
394bf215546Sopenharmony_ci        if (has_present_buffers) {
395bf215546Sopenharmony_ci            tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
396bf215546Sopenharmony_ci            tmplt.bind = NINE_BIND_PRESENTBUFFER_FLAGS;
397bf215546Sopenharmony_ci            tmplt.nr_samples = 0;
398bf215546Sopenharmony_ci            tmplt.nr_storage_samples = 0;
399bf215546Sopenharmony_ci            if (This->actx->linear_framebuffer)
400bf215546Sopenharmony_ci                tmplt.bind |= PIPE_BIND_LINEAR;
401bf215546Sopenharmony_ci            if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
402bf215546Sopenharmony_ci                tmplt.bind |= PIPE_BIND_RENDER_TARGET;
403bf215546Sopenharmony_ci            resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
404bf215546Sopenharmony_ci            pipe_resource_reference(&(This->present_buffers[i]), resource);
405bf215546Sopenharmony_ci        }
406bf215546Sopenharmony_ci        This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth, false);
407bf215546Sopenharmony_ci        pipe_resource_reference(&resource, NULL);
408bf215546Sopenharmony_ci        if (!This->present_handles[i]) {
409bf215546Sopenharmony_ci            return D3DERR_DRIVERINTERNALERROR;
410bf215546Sopenharmony_ci        }
411bf215546Sopenharmony_ci    }
412bf215546Sopenharmony_ci    if (pParams->EnableAutoDepthStencil) {
413bf215546Sopenharmony_ci        tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat);
414bf215546Sopenharmony_ci        tmplt.nr_samples = multisample_type;
415bf215546Sopenharmony_ci        tmplt.nr_storage_samples = multisample_type;
416bf215546Sopenharmony_ci        tmplt.format = d3d9_to_pipe_format_checked(This->screen,
417bf215546Sopenharmony_ci                                                   pParams->AutoDepthStencilFormat,
418bf215546Sopenharmony_ci                                                   PIPE_TEXTURE_2D,
419bf215546Sopenharmony_ci                                                   tmplt.nr_samples,
420bf215546Sopenharmony_ci                                                   tmplt.bind,
421bf215546Sopenharmony_ci                                                   FALSE, FALSE);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci        if (tmplt.format == PIPE_FORMAT_NONE)
424bf215546Sopenharmony_ci            return D3DERR_INVALIDCALL;
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci        if (This->zsbuf) {
427bf215546Sopenharmony_ci            resource = nine_resource_create_with_retry(pDevice, This->screen, &tmplt);
428bf215546Sopenharmony_ci            if (!resource) {
429bf215546Sopenharmony_ci                DBG("Failed to create pipe_resource for depth buffer.\n");
430bf215546Sopenharmony_ci                return D3DERR_OUTOFVIDEOMEMORY;
431bf215546Sopenharmony_ci            }
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci            NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType);
434bf215546Sopenharmony_ci            NineSurface9_SetResourceResize(This->zsbuf, resource);
435bf215546Sopenharmony_ci            pipe_resource_reference(&resource, NULL);
436bf215546Sopenharmony_ci        } else {
437bf215546Sopenharmony_ci            hr = NineDevice9_CreateDepthStencilSurface(pDevice,
438bf215546Sopenharmony_ci                                                       pParams->BackBufferWidth,
439bf215546Sopenharmony_ci                                                       pParams->BackBufferHeight,
440bf215546Sopenharmony_ci                                                       pParams->AutoDepthStencilFormat,
441bf215546Sopenharmony_ci                                                       pParams->MultiSampleType,
442bf215546Sopenharmony_ci                                                       pParams->MultiSampleQuality,
443bf215546Sopenharmony_ci                                                       0,
444bf215546Sopenharmony_ci                                                       (IDirect3DSurface9 **)&This->zsbuf,
445bf215546Sopenharmony_ci                                                       NULL);
446bf215546Sopenharmony_ci            if (FAILED(hr)) {
447bf215546Sopenharmony_ci                DBG("Failed to create ZS surface.\n");
448bf215546Sopenharmony_ci                return hr;
449bf215546Sopenharmony_ci            }
450bf215546Sopenharmony_ci            NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf));
451bf215546Sopenharmony_ci        }
452bf215546Sopenharmony_ci    }
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci    This->params = *pParams;
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci    return D3D_OK;
457bf215546Sopenharmony_ci}
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci/* Throttling: code adapted from the dri frontend */
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci/**
462bf215546Sopenharmony_ci * swap_fences_pop_front - pull a fence from the throttle queue
463bf215546Sopenharmony_ci *
464bf215546Sopenharmony_ci * If the throttle queue is filled to the desired number of fences,
465bf215546Sopenharmony_ci * pull fences off the queue until the number is less than the desired
466bf215546Sopenharmony_ci * number of fences, and return the last fence pulled.
467bf215546Sopenharmony_ci */
468bf215546Sopenharmony_cistatic struct pipe_fence_handle *
469bf215546Sopenharmony_ciswap_fences_pop_front(struct NineSwapChain9 *This)
470bf215546Sopenharmony_ci{
471bf215546Sopenharmony_ci    struct pipe_screen *screen = This->screen;
472bf215546Sopenharmony_ci    struct pipe_fence_handle *fence = NULL;
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci    if (This->desired_fences == 0)
475bf215546Sopenharmony_ci        return NULL;
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci    if (This->cur_fences >= This->desired_fences) {
478bf215546Sopenharmony_ci        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
479bf215546Sopenharmony_ci        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
480bf215546Sopenharmony_ci        This->tail &= DRI_SWAP_FENCES_MASK;
481bf215546Sopenharmony_ci        --This->cur_fences;
482bf215546Sopenharmony_ci    }
483bf215546Sopenharmony_ci    return fence;
484bf215546Sopenharmony_ci}
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci/**
488bf215546Sopenharmony_ci * swap_fences_see_front - same than swap_fences_pop_front without
489bf215546Sopenharmony_ci * pulling
490bf215546Sopenharmony_ci *
491bf215546Sopenharmony_ci */
492bf215546Sopenharmony_ci
493bf215546Sopenharmony_cistatic struct pipe_fence_handle *
494bf215546Sopenharmony_ciswap_fences_see_front(struct NineSwapChain9 *This)
495bf215546Sopenharmony_ci{
496bf215546Sopenharmony_ci    struct pipe_screen *screen = This->screen;
497bf215546Sopenharmony_ci    struct pipe_fence_handle *fence = NULL;
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci    if (This->desired_fences == 0)
500bf215546Sopenharmony_ci        return NULL;
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci    if (This->cur_fences >= This->desired_fences) {
503bf215546Sopenharmony_ci        screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
504bf215546Sopenharmony_ci    }
505bf215546Sopenharmony_ci    return fence;
506bf215546Sopenharmony_ci}
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci/**
510bf215546Sopenharmony_ci * swap_fences_push_back - push a fence onto the throttle queue at the back
511bf215546Sopenharmony_ci *
512bf215546Sopenharmony_ci * push a fence onto the throttle queue and pull fences of the queue
513bf215546Sopenharmony_ci * so that the desired number of fences are on the queue.
514bf215546Sopenharmony_ci */
515bf215546Sopenharmony_cistatic void
516bf215546Sopenharmony_ciswap_fences_push_back(struct NineSwapChain9 *This,
517bf215546Sopenharmony_ci                      struct pipe_fence_handle *fence)
518bf215546Sopenharmony_ci{
519bf215546Sopenharmony_ci    struct pipe_screen *screen = This->screen;
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci    if (!fence || This->desired_fences == 0)
522bf215546Sopenharmony_ci        return;
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci    while(This->cur_fences == This->desired_fences)
525bf215546Sopenharmony_ci        swap_fences_pop_front(This);
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci    This->cur_fences++;
528bf215546Sopenharmony_ci    screen->fence_reference(screen, &This->swap_fences[This->head++],
529bf215546Sopenharmony_ci                            fence);
530bf215546Sopenharmony_ci    This->head &= DRI_SWAP_FENCES_MASK;
531bf215546Sopenharmony_ci}
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci/**
535bf215546Sopenharmony_ci * swap_fences_unref - empty the throttle queue
536bf215546Sopenharmony_ci *
537bf215546Sopenharmony_ci * pulls fences of the throttle queue until it is empty.
538bf215546Sopenharmony_ci */
539bf215546Sopenharmony_cistatic void
540bf215546Sopenharmony_ciswap_fences_unref(struct NineSwapChain9 *This)
541bf215546Sopenharmony_ci{
542bf215546Sopenharmony_ci    struct pipe_screen *screen = This->screen;
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci    while(This->cur_fences) {
545bf215546Sopenharmony_ci        screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
546bf215546Sopenharmony_ci        This->tail &= DRI_SWAP_FENCES_MASK;
547bf215546Sopenharmony_ci        --This->cur_fences;
548bf215546Sopenharmony_ci    }
549bf215546Sopenharmony_ci}
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_civoid
552bf215546Sopenharmony_ciNineSwapChain9_dtor( struct NineSwapChain9 *This )
553bf215546Sopenharmony_ci{
554bf215546Sopenharmony_ci    unsigned i;
555bf215546Sopenharmony_ci
556bf215546Sopenharmony_ci    DBG("This=%p\n", This);
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci    if (This->pool)
559bf215546Sopenharmony_ci        _mesa_threadpool_destroy(This, This->pool);
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
562bf215546Sopenharmony_ci        if (This->pending_presentation[i])
563bf215546Sopenharmony_ci            FREE(This->pending_presentation[i]);
564bf215546Sopenharmony_ci    }
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci    for (i = 0; i < D3DPRESENT_BACK_BUFFERS_MAX_EX + 1; i++) {
567bf215546Sopenharmony_ci        if (This->present_handles_pending_release[i])
568bf215546Sopenharmony_ci            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles_pending_release[i]);
569bf215546Sopenharmony_ci    }
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci    for (i = 0; i < This->num_back_buffers; i++) {
572bf215546Sopenharmony_ci        if (This->buffers[i])
573bf215546Sopenharmony_ci            NineUnknown_Detach(NineUnknown(This->buffers[i]));
574bf215546Sopenharmony_ci        if (This->present_handles[i])
575bf215546Sopenharmony_ci            ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
576bf215546Sopenharmony_ci        if (This->present_buffers[i])
577bf215546Sopenharmony_ci            pipe_resource_reference(&(This->present_buffers[i]), NULL);
578bf215546Sopenharmony_ci    }
579bf215546Sopenharmony_ci    if (This->zsbuf)
580bf215546Sopenharmony_ci        NineUnknown_Unbind(NineUnknown(This->zsbuf));
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci    if (This->present)
583bf215546Sopenharmony_ci        ID3DPresent_Release(This->present);
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci    swap_fences_unref(This);
586bf215546Sopenharmony_ci    NineUnknown_dtor(&This->base);
587bf215546Sopenharmony_ci}
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_cistatic void
590bf215546Sopenharmony_cicreate_present_buffer( struct NineSwapChain9 *This,
591bf215546Sopenharmony_ci                       unsigned int width, unsigned int height,
592bf215546Sopenharmony_ci                       struct pipe_resource **resource,
593bf215546Sopenharmony_ci                       D3DWindowBuffer **present_handle)
594bf215546Sopenharmony_ci{
595bf215546Sopenharmony_ci    struct pipe_resource tmplt;
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci    memset(&tmplt, 0, sizeof(tmplt));
598bf215546Sopenharmony_ci    tmplt.target = PIPE_TEXTURE_2D;
599bf215546Sopenharmony_ci    tmplt.width0 = width;
600bf215546Sopenharmony_ci    tmplt.height0 = height;
601bf215546Sopenharmony_ci    tmplt.depth0 = 1;
602bf215546Sopenharmony_ci    tmplt.last_level = 0;
603bf215546Sopenharmony_ci    tmplt.array_size = 1;
604bf215546Sopenharmony_ci    tmplt.usage = PIPE_USAGE_DEFAULT;
605bf215546Sopenharmony_ci    tmplt.flags = 0;
606bf215546Sopenharmony_ci    tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
607bf215546Sopenharmony_ci    tmplt.bind = NINE_BIND_BACKBUFFER_FLAGS |
608bf215546Sopenharmony_ci                 NINE_BIND_PRESENTBUFFER_FLAGS;
609bf215546Sopenharmony_ci    tmplt.nr_samples = 0;
610bf215546Sopenharmony_ci    if (This->actx->linear_framebuffer)
611bf215546Sopenharmony_ci        tmplt.bind |= PIPE_BIND_LINEAR;
612bf215546Sopenharmony_ci    *resource = nine_resource_create_with_retry(This->base.device, This->screen, &tmplt);
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci    *present_handle = D3DWindowBuffer_create(This, *resource, 24, true);
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci    if (!*present_handle) {
617bf215546Sopenharmony_ci        pipe_resource_reference(resource, NULL);
618bf215546Sopenharmony_ci    }
619bf215546Sopenharmony_ci}
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_cistatic void
622bf215546Sopenharmony_cihandle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
623bf215546Sopenharmony_ci{
624bf215546Sopenharmony_ci    struct NineDevice9 *device = This->base.device;
625bf215546Sopenharmony_ci    struct pipe_blit_info blit;
626bf215546Sopenharmony_ci    struct pipe_context *pipe;
627bf215546Sopenharmony_ci
628bf215546Sopenharmony_ci    if (device->cursor.software && device->cursor.visible && device->cursor.w) {
629bf215546Sopenharmony_ci        memset(&blit, 0, sizeof(blit));
630bf215546Sopenharmony_ci        blit.src.resource = device->cursor.image;
631bf215546Sopenharmony_ci        blit.src.level = 0;
632bf215546Sopenharmony_ci        blit.src.format = device->cursor.image->format;
633bf215546Sopenharmony_ci        blit.src.box.x = 0;
634bf215546Sopenharmony_ci        blit.src.box.y = 0;
635bf215546Sopenharmony_ci        blit.src.box.z = 0;
636bf215546Sopenharmony_ci        blit.src.box.depth = 1;
637bf215546Sopenharmony_ci        blit.src.box.width = device->cursor.w;
638bf215546Sopenharmony_ci        blit.src.box.height = device->cursor.h;
639bf215546Sopenharmony_ci
640bf215546Sopenharmony_ci        blit.dst.resource = resource;
641bf215546Sopenharmony_ci        blit.dst.level = 0;
642bf215546Sopenharmony_ci        blit.dst.format = resource->format;
643bf215546Sopenharmony_ci        blit.dst.box.z = 0;
644bf215546Sopenharmony_ci        blit.dst.box.depth = 1;
645bf215546Sopenharmony_ci
646bf215546Sopenharmony_ci        blit.mask = PIPE_MASK_RGBA;
647bf215546Sopenharmony_ci        blit.filter = PIPE_TEX_FILTER_NEAREST;
648bf215546Sopenharmony_ci        blit.scissor_enable = FALSE;
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_ci        /* NOTE: blit messes up when box.x + box.width < 0, fix driver
651bf215546Sopenharmony_ci         * NOTE2: device->cursor.pos contains coordinates relative to the screen.
652bf215546Sopenharmony_ci         * This happens to be also the position of the cursor when we are fullscreen.
653bf215546Sopenharmony_ci         * We don't use sw cursor for Windowed mode */
654bf215546Sopenharmony_ci        blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
655bf215546Sopenharmony_ci        blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
656bf215546Sopenharmony_ci        blit.dst.box.width = blit.src.box.width;
657bf215546Sopenharmony_ci        blit.dst.box.height = blit.src.box.height;
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_ci        DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
660bf215546Sopenharmony_ci            blit.src.box.width, blit.src.box.height,
661bf215546Sopenharmony_ci            blit.dst.box.x, blit.dst.box.y);
662bf215546Sopenharmony_ci
663bf215546Sopenharmony_ci        blit.alpha_blend = TRUE;
664bf215546Sopenharmony_ci        pipe = NineDevice9_GetPipe(This->base.device);
665bf215546Sopenharmony_ci        pipe->blit(pipe, &blit);
666bf215546Sopenharmony_ci    }
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci    if (device->hud && resource) {
669bf215546Sopenharmony_ci        /* Implicit use of context pipe */
670bf215546Sopenharmony_ci        (void)NineDevice9_GetPipe(This->base.device);
671bf215546Sopenharmony_ci        hud_run(device->hud, NULL, resource); /* XXX: no offset */
672bf215546Sopenharmony_ci        /* HUD doesn't clobber stipple */
673bf215546Sopenharmony_ci        nine_state_restore_non_cso(device);
674bf215546Sopenharmony_ci    }
675bf215546Sopenharmony_ci}
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_cistruct end_present_struct {
678bf215546Sopenharmony_ci    struct pipe_screen *screen;
679bf215546Sopenharmony_ci    struct pipe_fence_handle *fence_to_wait;
680bf215546Sopenharmony_ci    ID3DPresent *present;
681bf215546Sopenharmony_ci    D3DWindowBuffer *present_handle;
682bf215546Sopenharmony_ci    BOOL *pending_presentation;
683bf215546Sopenharmony_ci    HWND hDestWindowOverride;
684bf215546Sopenharmony_ci};
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_cistatic void work_present(void *data)
687bf215546Sopenharmony_ci{
688bf215546Sopenharmony_ci    struct end_present_struct *work = data;
689bf215546Sopenharmony_ci    if (work->fence_to_wait) {
690bf215546Sopenharmony_ci        (void) work->screen->fence_finish(work->screen, NULL, work->fence_to_wait, PIPE_TIMEOUT_INFINITE);
691bf215546Sopenharmony_ci        work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL);
692bf215546Sopenharmony_ci    }
693bf215546Sopenharmony_ci    ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0);
694bf215546Sopenharmony_ci    p_atomic_set(work->pending_presentation, FALSE);
695bf215546Sopenharmony_ci    free(work);
696bf215546Sopenharmony_ci}
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_cistatic void pend_present(struct NineSwapChain9 *This,
699bf215546Sopenharmony_ci                         struct pipe_fence_handle *fence,
700bf215546Sopenharmony_ci                         HWND hDestWindowOverride)
701bf215546Sopenharmony_ci{
702bf215546Sopenharmony_ci    struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct));
703bf215546Sopenharmony_ci
704bf215546Sopenharmony_ci    work->screen = This->screen;
705bf215546Sopenharmony_ci    This->screen->fence_reference(This->screen, &work->fence_to_wait, fence);
706bf215546Sopenharmony_ci    work->present = This->present;
707bf215546Sopenharmony_ci    work->present_handle = This->present_handles[0];
708bf215546Sopenharmony_ci    work->hDestWindowOverride = hDestWindowOverride;
709bf215546Sopenharmony_ci    work->pending_presentation = This->pending_presentation[0];
710bf215546Sopenharmony_ci    p_atomic_set(work->pending_presentation, TRUE);
711bf215546Sopenharmony_ci    This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work);
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci    return;
714bf215546Sopenharmony_ci}
715bf215546Sopenharmony_ci
716bf215546Sopenharmony_cistatic inline HRESULT
717bf215546Sopenharmony_cipresent( struct NineSwapChain9 *This,
718bf215546Sopenharmony_ci         const RECT *pSourceRect,
719bf215546Sopenharmony_ci         const RECT *pDestRect,
720bf215546Sopenharmony_ci         HWND hDestWindowOverride,
721bf215546Sopenharmony_ci         const RGNDATA *pDirtyRegion,
722bf215546Sopenharmony_ci         DWORD dwFlags )
723bf215546Sopenharmony_ci{
724bf215546Sopenharmony_ci    struct pipe_context *pipe;
725bf215546Sopenharmony_ci    struct pipe_resource *resource;
726bf215546Sopenharmony_ci    struct pipe_fence_handle *fence;
727bf215546Sopenharmony_ci    HRESULT hr;
728bf215546Sopenharmony_ci    struct pipe_blit_info blit;
729bf215546Sopenharmony_ci    int target_width, target_height, target_depth, i;
730bf215546Sopenharmony_ci    RECT source_rect;
731bf215546Sopenharmony_ci    RECT dest_rect;
732bf215546Sopenharmony_ci
733bf215546Sopenharmony_ci    DBG("present: This=%p pSourceRect=%p pDestRect=%p "
734bf215546Sopenharmony_ci        "pDirtyRegion=%p hDestWindowOverride=%p"
735bf215546Sopenharmony_ci        "dwFlags=%d resource=%p\n",
736bf215546Sopenharmony_ci        This, pSourceRect, pDestRect, pDirtyRegion,
737bf215546Sopenharmony_ci        hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci    /* We can choose to only update pDirtyRegion, but the backend can choose
740bf215546Sopenharmony_ci     * to update everything. Let's ignore */
741bf215546Sopenharmony_ci    (void) pDirtyRegion;
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci    resource = This->buffers[0]->base.resource;
744bf215546Sopenharmony_ci
745bf215546Sopenharmony_ci    if (pSourceRect) {
746bf215546Sopenharmony_ci        DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
747bf215546Sopenharmony_ci            pSourceRect->left, pSourceRect->right,
748bf215546Sopenharmony_ci            pSourceRect->top, pSourceRect->bottom);
749bf215546Sopenharmony_ci        source_rect = *pSourceRect;
750bf215546Sopenharmony_ci        if (source_rect.top == 0 &&
751bf215546Sopenharmony_ci            source_rect.left == 0 &&
752bf215546Sopenharmony_ci            source_rect.bottom == resource->height0 &&
753bf215546Sopenharmony_ci            source_rect.right == resource->width0)
754bf215546Sopenharmony_ci            pSourceRect = NULL;
755bf215546Sopenharmony_ci        /* TODO: Handle more of pSourceRect.
756bf215546Sopenharmony_ci         * Currently we should support:
757bf215546Sopenharmony_ci         * . When there is no pSourceRect
758bf215546Sopenharmony_ci         * . When pSourceRect is the full buffer.
759bf215546Sopenharmony_ci         */
760bf215546Sopenharmony_ci    }
761bf215546Sopenharmony_ci    if (pDestRect) {
762bf215546Sopenharmony_ci        DBG("pDestRect = (%u..%u)x(%u..%u)\n",
763bf215546Sopenharmony_ci            pDestRect->left, pDestRect->right,
764bf215546Sopenharmony_ci            pDestRect->top, pDestRect->bottom);
765bf215546Sopenharmony_ci        dest_rect = *pDestRect;
766bf215546Sopenharmony_ci    }
767bf215546Sopenharmony_ci
768bf215546Sopenharmony_ci    if (This->rendering_done)
769bf215546Sopenharmony_ci        goto bypass_rendering;
770bf215546Sopenharmony_ci
771bf215546Sopenharmony_ci    if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
772bf215546Sopenharmony_ci        handle_draw_cursor_and_hud(This, resource);
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci    hr = ID3DPresent_GetWindowInfo(This->present, hDestWindowOverride, &target_width, &target_height, &target_depth);
775bf215546Sopenharmony_ci    (void)target_depth;
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci    /* Can happen with old Wine (presentation can still succeed),
778bf215546Sopenharmony_ci     * or at window destruction.
779bf215546Sopenharmony_ci     * Also disable for very old wine as D3DWindowBuffer_release
780bf215546Sopenharmony_ci     * cannot do the DestroyD3DWindowBuffer workaround. */
781bf215546Sopenharmony_ci    if (FAILED(hr) || target_width == 0 || target_height == 0 ||
782bf215546Sopenharmony_ci        This->base.device->minor_version_num <= 2) {
783bf215546Sopenharmony_ci        target_width = resource->width0;
784bf215546Sopenharmony_ci        target_height = resource->height0;
785bf215546Sopenharmony_ci    }
786bf215546Sopenharmony_ci
787bf215546Sopenharmony_ci    if (pDestRect) {
788bf215546Sopenharmony_ci        dest_rect.top = MAX2(0, dest_rect.top);
789bf215546Sopenharmony_ci        dest_rect.left = MAX2(0, dest_rect.left);
790bf215546Sopenharmony_ci        dest_rect.bottom = MIN2(target_height, dest_rect.bottom);
791bf215546Sopenharmony_ci        dest_rect.right = MIN2(target_width, dest_rect.right);
792bf215546Sopenharmony_ci        target_height = dest_rect.bottom - dest_rect.top;
793bf215546Sopenharmony_ci        target_width = dest_rect.right - dest_rect.left;
794bf215546Sopenharmony_ci    }
795bf215546Sopenharmony_ci
796bf215546Sopenharmony_ci    /* Switch to using presentation buffers on window resize.
797bf215546Sopenharmony_ci     * Note: Most apps should resize the d3d back buffers when
798bf215546Sopenharmony_ci     * a window resize is detected, which will result in a call to
799bf215546Sopenharmony_ci     * NineSwapChain9_Resize. Thus everything will get released,
800bf215546Sopenharmony_ci     * and it will switch back to not using separate presentation
801bf215546Sopenharmony_ci     * buffers. */
802bf215546Sopenharmony_ci    if (!This->present_buffers[0] &&
803bf215546Sopenharmony_ci        (target_width != resource->width0 || target_height != resource->height0)) {
804bf215546Sopenharmony_ci        BOOL failure = false;
805bf215546Sopenharmony_ci        struct pipe_resource *new_resource[This->num_back_buffers];
806bf215546Sopenharmony_ci        D3DWindowBuffer *new_handles[This->num_back_buffers];
807bf215546Sopenharmony_ci        for (i = 0; i < This->num_back_buffers; i++) {
808bf215546Sopenharmony_ci            /* Note: if (!new_handles[i]), new_resource[i]
809bf215546Sopenharmony_ci             * gets released and contains NULL */
810bf215546Sopenharmony_ci            create_present_buffer(This, target_width, target_height, &new_resource[i], &new_handles[i]);
811bf215546Sopenharmony_ci            if (!new_handles[i])
812bf215546Sopenharmony_ci                failure = true;
813bf215546Sopenharmony_ci        }
814bf215546Sopenharmony_ci        if (failure) {
815bf215546Sopenharmony_ci            for (i = 0; i < This->num_back_buffers; i++) {
816bf215546Sopenharmony_ci                if (new_resource[i])
817bf215546Sopenharmony_ci                    pipe_resource_reference(&new_resource[i], NULL);
818bf215546Sopenharmony_ci                if (new_handles[i])
819bf215546Sopenharmony_ci                    D3DWindowBuffer_release(This, new_handles[i]);
820bf215546Sopenharmony_ci            }
821bf215546Sopenharmony_ci        } else {
822bf215546Sopenharmony_ci            for (i = 0; i < This->num_back_buffers; i++) {
823bf215546Sopenharmony_ci                D3DWindowBuffer_release(This, This->present_handles[i]);
824bf215546Sopenharmony_ci                This->present_handles[i] = new_handles[i];
825bf215546Sopenharmony_ci                pipe_resource_reference(&This->present_buffers[i], new_resource[i]);
826bf215546Sopenharmony_ci                pipe_resource_reference(&new_resource[i], NULL);
827bf215546Sopenharmony_ci            }
828bf215546Sopenharmony_ci        }
829bf215546Sopenharmony_ci    }
830bf215546Sopenharmony_ci
831bf215546Sopenharmony_ci    pipe = NineDevice9_GetPipe(This->base.device);
832bf215546Sopenharmony_ci
833bf215546Sopenharmony_ci    if (This->present_buffers[0]) {
834bf215546Sopenharmony_ci        memset(&blit, 0, sizeof(blit));
835bf215546Sopenharmony_ci        blit.src.resource = resource;
836bf215546Sopenharmony_ci        blit.src.level = 0; /* Note: This->buffers[0]->level should always be 0 */
837bf215546Sopenharmony_ci        blit.src.format = resource->format;
838bf215546Sopenharmony_ci        blit.src.box.z = 0;
839bf215546Sopenharmony_ci        blit.src.box.depth = 1;
840bf215546Sopenharmony_ci        blit.src.box.x = 0;
841bf215546Sopenharmony_ci        blit.src.box.y = 0;
842bf215546Sopenharmony_ci        blit.src.box.width = resource->width0;
843bf215546Sopenharmony_ci        blit.src.box.height = resource->height0;
844bf215546Sopenharmony_ci
845bf215546Sopenharmony_ci        /* Reallocate a new presentation buffer if the target window
846bf215546Sopenharmony_ci         * size has changed */
847bf215546Sopenharmony_ci        if (target_width != This->present_buffers[0]->width0 ||
848bf215546Sopenharmony_ci            target_height != This->present_buffers[0]->height0) {
849bf215546Sopenharmony_ci            struct pipe_resource *new_resource;
850bf215546Sopenharmony_ci            D3DWindowBuffer *new_handle;
851bf215546Sopenharmony_ci
852bf215546Sopenharmony_ci            create_present_buffer(This, target_width, target_height, &new_resource, &new_handle);
853bf215546Sopenharmony_ci            /* Switch to the new buffer */
854bf215546Sopenharmony_ci            if (new_handle) {
855bf215546Sopenharmony_ci                D3DWindowBuffer_release(This, This->present_handles[0]);
856bf215546Sopenharmony_ci                This->present_handles[0] = new_handle;
857bf215546Sopenharmony_ci                pipe_resource_reference(&This->present_buffers[0], new_resource);
858bf215546Sopenharmony_ci                pipe_resource_reference(&new_resource, NULL);
859bf215546Sopenharmony_ci            }
860bf215546Sopenharmony_ci        }
861bf215546Sopenharmony_ci
862bf215546Sopenharmony_ci        resource = This->present_buffers[0];
863bf215546Sopenharmony_ci
864bf215546Sopenharmony_ci        blit.dst.resource = resource;
865bf215546Sopenharmony_ci        blit.dst.level = 0;
866bf215546Sopenharmony_ci        blit.dst.format = resource->format;
867bf215546Sopenharmony_ci        blit.dst.box.z = 0;
868bf215546Sopenharmony_ci        blit.dst.box.depth = 1;
869bf215546Sopenharmony_ci        blit.dst.box.x = 0;
870bf215546Sopenharmony_ci        blit.dst.box.y = 0;
871bf215546Sopenharmony_ci        blit.dst.box.width = resource->width0;
872bf215546Sopenharmony_ci        blit.dst.box.height = resource->height0;
873bf215546Sopenharmony_ci
874bf215546Sopenharmony_ci        blit.mask = PIPE_MASK_RGBA;
875bf215546Sopenharmony_ci        blit.filter = (blit.dst.box.width == blit.src.box.width &&
876bf215546Sopenharmony_ci                       blit.dst.box.height == blit.src.box.height) ?
877bf215546Sopenharmony_ci                          PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR;
878bf215546Sopenharmony_ci        blit.scissor_enable = FALSE;
879bf215546Sopenharmony_ci        blit.alpha_blend = FALSE;
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci        pipe->blit(pipe, &blit);
882bf215546Sopenharmony_ci    }
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_ci    /* The resource we present has to resolve fast clears
885bf215546Sopenharmony_ci     * if needed (and other things) */
886bf215546Sopenharmony_ci    pipe->flush_resource(pipe, resource);
887bf215546Sopenharmony_ci
888bf215546Sopenharmony_ci    if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
889bf215546Sopenharmony_ci        handle_draw_cursor_and_hud(This, resource);
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci    fence = NULL;
892bf215546Sopenharmony_ci    /* When threadpool is enabled, we don't submit before the fence
893bf215546Sopenharmony_ci     * tells us rendering was finished, thus we can flush async there */
894bf215546Sopenharmony_ci    pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME | (This->enable_threadpool ? PIPE_FLUSH_ASYNC : 0));
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_ci    /* Present now for thread_submit, because we have the fence.
897bf215546Sopenharmony_ci     * It's possible we return WASSTILLDRAWING and still Present,
898bf215546Sopenharmony_ci     * but it should be fine. */
899bf215546Sopenharmony_ci    if (This->enable_threadpool)
900bf215546Sopenharmony_ci        pend_present(This, fence, hDestWindowOverride);
901bf215546Sopenharmony_ci    if (fence) {
902bf215546Sopenharmony_ci        swap_fences_push_back(This, fence);
903bf215546Sopenharmony_ci        This->screen->fence_reference(This->screen, &fence, NULL);
904bf215546Sopenharmony_ci    }
905bf215546Sopenharmony_ci
906bf215546Sopenharmony_ci    This->rendering_done = TRUE;
907bf215546Sopenharmony_cibypass_rendering:
908bf215546Sopenharmony_ci
909bf215546Sopenharmony_ci    if (dwFlags & D3DPRESENT_DONOTWAIT) {
910bf215546Sopenharmony_ci        UNTESTED(2);
911bf215546Sopenharmony_ci        BOOL still_draw = FALSE;
912bf215546Sopenharmony_ci        fence = swap_fences_see_front(This);
913bf215546Sopenharmony_ci        if (fence) {
914bf215546Sopenharmony_ci            still_draw = !This->screen->fence_finish(This->screen, NULL, fence, 0);
915bf215546Sopenharmony_ci            This->screen->fence_reference(This->screen, &fence, NULL);
916bf215546Sopenharmony_ci        }
917bf215546Sopenharmony_ci        if (still_draw)
918bf215546Sopenharmony_ci            return D3DERR_WASSTILLDRAWING;
919bf215546Sopenharmony_ci    }
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci    /* Throttle rendering if needed */
922bf215546Sopenharmony_ci    fence = swap_fences_pop_front(This);
923bf215546Sopenharmony_ci    if (fence) {
924bf215546Sopenharmony_ci        (void) This->screen->fence_finish(This->screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
925bf215546Sopenharmony_ci        This->screen->fence_reference(This->screen, &fence, NULL);
926bf215546Sopenharmony_ci    }
927bf215546Sopenharmony_ci
928bf215546Sopenharmony_ci    This->rendering_done = FALSE;
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci    if (!This->enable_threadpool) {
931bf215546Sopenharmony_ci        This->tasks[0]=NULL;
932bf215546Sopenharmony_ci
933bf215546Sopenharmony_ci        hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect ? &dest_rect : NULL, NULL, dwFlags);
934bf215546Sopenharmony_ci
935bf215546Sopenharmony_ci        if (FAILED(hr)) { UNTESTED(3);return hr; }
936bf215546Sopenharmony_ci    }
937bf215546Sopenharmony_ci
938bf215546Sopenharmony_ci    This->base.device->end_scene_since_present = 0;
939bf215546Sopenharmony_ci    This->base.device->frame_count++;
940bf215546Sopenharmony_ci    return D3D_OK;
941bf215546Sopenharmony_ci}
942bf215546Sopenharmony_ci
943bf215546Sopenharmony_ciHRESULT NINE_WINAPI
944bf215546Sopenharmony_ciNineSwapChain9_Present( struct NineSwapChain9 *This,
945bf215546Sopenharmony_ci                        const RECT *pSourceRect,
946bf215546Sopenharmony_ci                        const RECT *pDestRect,
947bf215546Sopenharmony_ci                        HWND hDestWindowOverride,
948bf215546Sopenharmony_ci                        const RGNDATA *pDirtyRegion,
949bf215546Sopenharmony_ci                        DWORD dwFlags )
950bf215546Sopenharmony_ci{
951bf215546Sopenharmony_ci    struct pipe_resource *res = NULL;
952bf215546Sopenharmony_ci    D3DWindowBuffer *handle_temp;
953bf215546Sopenharmony_ci    struct threadpool_task *task_temp;
954bf215546Sopenharmony_ci    BOOL *pending_presentation_temp;
955bf215546Sopenharmony_ci    int i;
956bf215546Sopenharmony_ci    HRESULT hr;
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci    DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
959bf215546Sopenharmony_ci        "pDirtyRegion=%p dwFlags=%d\n",
960bf215546Sopenharmony_ci        This, pSourceRect, pDestRect, hDestWindowOverride,
961bf215546Sopenharmony_ci        pDirtyRegion,dwFlags);
962bf215546Sopenharmony_ci
963bf215546Sopenharmony_ci    if (This->base.device->ex) {
964bf215546Sopenharmony_ci        if (NineSwapChain9_GetOccluded(This)) {
965bf215546Sopenharmony_ci            DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n");
966bf215546Sopenharmony_ci            return S_PRESENT_OCCLUDED;
967bf215546Sopenharmony_ci        }
968bf215546Sopenharmony_ci    } else {
969bf215546Sopenharmony_ci        if (NineSwapChain9_GetOccluded(This) ||
970bf215546Sopenharmony_ci            NineSwapChain9_ResolutionMismatch(This)) {
971bf215546Sopenharmony_ci            This->base.device->device_needs_reset = TRUE;
972bf215546Sopenharmony_ci        }
973bf215546Sopenharmony_ci        if (This->base.device->device_needs_reset) {
974bf215546Sopenharmony_ci            DBG("Device is lost. Returning D3DERR_DEVICELOST.\n");
975bf215546Sopenharmony_ci            return D3DERR_DEVICELOST;
976bf215546Sopenharmony_ci        }
977bf215546Sopenharmony_ci    }
978bf215546Sopenharmony_ci
979bf215546Sopenharmony_ci    nine_csmt_process(This->base.device);
980bf215546Sopenharmony_ci
981bf215546Sopenharmony_ci    hr = present(This, pSourceRect, pDestRect,
982bf215546Sopenharmony_ci                 hDestWindowOverride, pDirtyRegion, dwFlags);
983bf215546Sopenharmony_ci    if (hr == D3DERR_WASSTILLDRAWING)
984bf215546Sopenharmony_ci        return hr;
985bf215546Sopenharmony_ci
986bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 2 &&
987bf215546Sopenharmony_ci        This->actx->discard_delayed_release &&
988bf215546Sopenharmony_ci        This->params.SwapEffect == D3DSWAPEFFECT_DISCARD &&
989bf215546Sopenharmony_ci        This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
990bf215546Sopenharmony_ci        int next_buffer = -1;
991bf215546Sopenharmony_ci
992bf215546Sopenharmony_ci        while (next_buffer == -1) {
993bf215546Sopenharmony_ci            /* Find a free backbuffer */
994bf215546Sopenharmony_ci            for (i = 1; i < This->num_back_buffers; i++) {
995bf215546Sopenharmony_ci                if (!p_atomic_read(This->pending_presentation[i]) &&
996bf215546Sopenharmony_ci                    ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) {
997bf215546Sopenharmony_ci                    DBG("Found buffer released: %d\n", i);
998bf215546Sopenharmony_ci                    next_buffer = i;
999bf215546Sopenharmony_ci                    break;
1000bf215546Sopenharmony_ci                }
1001bf215546Sopenharmony_ci            }
1002bf215546Sopenharmony_ci            if (next_buffer == -1) {
1003bf215546Sopenharmony_ci                DBG("Found no buffer released. Waiting for event\n");
1004bf215546Sopenharmony_ci                ID3DPresent_WaitBufferReleaseEvent(This->present);
1005bf215546Sopenharmony_ci            }
1006bf215546Sopenharmony_ci        }
1007bf215546Sopenharmony_ci
1008bf215546Sopenharmony_ci        /* Free the task (we already checked it is finished) */
1009bf215546Sopenharmony_ci        if (This->tasks[next_buffer])
1010bf215546Sopenharmony_ci            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[next_buffer]));
1011bf215546Sopenharmony_ci        assert(!*This->pending_presentation[next_buffer] && !This->tasks[next_buffer]);
1012bf215546Sopenharmony_ci        This->tasks[next_buffer] = This->tasks[0];
1013bf215546Sopenharmony_ci        This->tasks[0] = NULL;
1014bf215546Sopenharmony_ci        pending_presentation_temp = This->pending_presentation[next_buffer];
1015bf215546Sopenharmony_ci        This->pending_presentation[next_buffer] = This->pending_presentation[0];
1016bf215546Sopenharmony_ci        This->pending_presentation[0] = pending_presentation_temp;
1017bf215546Sopenharmony_ci
1018bf215546Sopenharmony_ci        /* Switch with the released buffer */
1019bf215546Sopenharmony_ci        pipe_resource_reference(&res, This->buffers[0]->base.resource);
1020bf215546Sopenharmony_ci        NineSurface9_SetResourceResize(
1021bf215546Sopenharmony_ci            This->buffers[0], This->buffers[next_buffer]->base.resource);
1022bf215546Sopenharmony_ci        NineSurface9_SetResourceResize(
1023bf215546Sopenharmony_ci            This->buffers[next_buffer], res);
1024bf215546Sopenharmony_ci        pipe_resource_reference(&res, NULL);
1025bf215546Sopenharmony_ci
1026bf215546Sopenharmony_ci        if (This->present_buffers[0]) {
1027bf215546Sopenharmony_ci            pipe_resource_reference(&res, This->present_buffers[0]);
1028bf215546Sopenharmony_ci            pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]);
1029bf215546Sopenharmony_ci            pipe_resource_reference(&This->present_buffers[next_buffer], res);
1030bf215546Sopenharmony_ci            pipe_resource_reference(&res, NULL);
1031bf215546Sopenharmony_ci        }
1032bf215546Sopenharmony_ci
1033bf215546Sopenharmony_ci        handle_temp = This->present_handles[0];
1034bf215546Sopenharmony_ci        This->present_handles[0] = This->present_handles[next_buffer];
1035bf215546Sopenharmony_ci        This->present_handles[next_buffer] = handle_temp;
1036bf215546Sopenharmony_ci    } else {
1037bf215546Sopenharmony_ci        switch (This->params.SwapEffect) {
1038bf215546Sopenharmony_ci            case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */
1039bf215546Sopenharmony_ci            case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */
1040bf215546Sopenharmony_ci            case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */
1041bf215546Sopenharmony_ci            case D3DSWAPEFFECT_FLIP:
1042bf215546Sopenharmony_ci                /* rotate the queue */
1043bf215546Sopenharmony_ci                pipe_resource_reference(&res, This->buffers[0]->base.resource);
1044bf215546Sopenharmony_ci                for (i = 1; i < This->num_back_buffers; i++) {
1045bf215546Sopenharmony_ci                    NineSurface9_SetResourceResize(This->buffers[i - 1],
1046bf215546Sopenharmony_ci                                                   This->buffers[i]->base.resource);
1047bf215546Sopenharmony_ci                }
1048bf215546Sopenharmony_ci                NineSurface9_SetResourceResize(
1049bf215546Sopenharmony_ci                    This->buffers[This->num_back_buffers - 1], res);
1050bf215546Sopenharmony_ci                pipe_resource_reference(&res, NULL);
1051bf215546Sopenharmony_ci
1052bf215546Sopenharmony_ci                if (This->present_buffers[0]) {
1053bf215546Sopenharmony_ci                    pipe_resource_reference(&res, This->present_buffers[0]);
1054bf215546Sopenharmony_ci                    for (i = 1; i < This->num_back_buffers; i++)
1055bf215546Sopenharmony_ci                        pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
1056bf215546Sopenharmony_ci                    pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res);
1057bf215546Sopenharmony_ci                    pipe_resource_reference(&res, NULL);
1058bf215546Sopenharmony_ci                }
1059bf215546Sopenharmony_ci
1060bf215546Sopenharmony_ci                handle_temp = This->present_handles[0];
1061bf215546Sopenharmony_ci                for (i = 1; i < This->num_back_buffers; i++) {
1062bf215546Sopenharmony_ci                    This->present_handles[i-1] = This->present_handles[i];
1063bf215546Sopenharmony_ci                }
1064bf215546Sopenharmony_ci                This->present_handles[This->num_back_buffers - 1] = handle_temp;
1065bf215546Sopenharmony_ci                task_temp = This->tasks[0];
1066bf215546Sopenharmony_ci                for (i = 1; i < This->num_back_buffers; i++) {
1067bf215546Sopenharmony_ci                    This->tasks[i-1] = This->tasks[i];
1068bf215546Sopenharmony_ci                }
1069bf215546Sopenharmony_ci                This->tasks[This->num_back_buffers - 1] = task_temp;
1070bf215546Sopenharmony_ci                pending_presentation_temp = This->pending_presentation[0];
1071bf215546Sopenharmony_ci                for (i = 1; i < This->num_back_buffers; i++) {
1072bf215546Sopenharmony_ci                    This->pending_presentation[i-1] = This->pending_presentation[i];
1073bf215546Sopenharmony_ci                }
1074bf215546Sopenharmony_ci                This->pending_presentation[This->num_back_buffers - 1] = pending_presentation_temp;
1075bf215546Sopenharmony_ci                break;
1076bf215546Sopenharmony_ci
1077bf215546Sopenharmony_ci            case D3DSWAPEFFECT_COPY:
1078bf215546Sopenharmony_ci                /* do nothing */
1079bf215546Sopenharmony_ci                break;
1080bf215546Sopenharmony_ci        }
1081bf215546Sopenharmony_ci
1082bf215546Sopenharmony_ci        if (This->tasks[0])
1083bf215546Sopenharmony_ci            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
1084bf215546Sopenharmony_ci        assert(!*This->pending_presentation[0]);
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci        ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
1087bf215546Sopenharmony_ci    }
1088bf215546Sopenharmony_ci
1089bf215546Sopenharmony_ci    This->base.device->context.changed.group |= NINE_STATE_FB;
1090bf215546Sopenharmony_ci
1091bf215546Sopenharmony_ci    return hr;
1092bf215546Sopenharmony_ci}
1093bf215546Sopenharmony_ci
1094bf215546Sopenharmony_ciHRESULT NINE_WINAPI
1095bf215546Sopenharmony_ciNineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
1096bf215546Sopenharmony_ci                                   IDirect3DSurface9 *pDestSurface )
1097bf215546Sopenharmony_ci{
1098bf215546Sopenharmony_ci    struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
1099bf215546Sopenharmony_ci    struct NineDevice9 *pDevice = This->base.device;
1100bf215546Sopenharmony_ci    unsigned int width, height;
1101bf215546Sopenharmony_ci    struct pipe_resource *temp_resource;
1102bf215546Sopenharmony_ci    struct NineSurface9 *temp_surface;
1103bf215546Sopenharmony_ci    D3DWindowBuffer *temp_handle;
1104bf215546Sopenharmony_ci    D3DSURFACE_DESC desc;
1105bf215546Sopenharmony_ci    HRESULT hr;
1106bf215546Sopenharmony_ci
1107bf215546Sopenharmony_ci    DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
1108bf215546Sopenharmony_ci        This, pDestSurface);
1109bf215546Sopenharmony_ci
1110bf215546Sopenharmony_ci    user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
1111bf215546Sopenharmony_ci
1112bf215546Sopenharmony_ci    width = dest_surface->desc.Width;
1113bf215546Sopenharmony_ci    height = dest_surface->desc.Height;
1114bf215546Sopenharmony_ci
1115bf215546Sopenharmony_ci    /* Note: front window size and destination size are supposed
1116bf215546Sopenharmony_ci     * to match. However it's not very clear what should get taken in Windowed
1117bf215546Sopenharmony_ci     * mode. It may need a fix */
1118bf215546Sopenharmony_ci    create_present_buffer(This, width, height, &temp_resource, &temp_handle);
1119bf215546Sopenharmony_ci
1120bf215546Sopenharmony_ci    if (!temp_resource || !temp_handle) {
1121bf215546Sopenharmony_ci        return D3DERR_INVALIDCALL;
1122bf215546Sopenharmony_ci    }
1123bf215546Sopenharmony_ci
1124bf215546Sopenharmony_ci    desc.Type = D3DRTYPE_SURFACE;
1125bf215546Sopenharmony_ci    desc.Pool = D3DPOOL_DEFAULT;
1126bf215546Sopenharmony_ci    desc.MultiSampleType = D3DMULTISAMPLE_NONE;
1127bf215546Sopenharmony_ci    desc.MultiSampleQuality = 0;
1128bf215546Sopenharmony_ci    desc.Width = width;
1129bf215546Sopenharmony_ci    desc.Height = height;
1130bf215546Sopenharmony_ci    /* NineSurface9_CopyDefaultToMem needs same format. */
1131bf215546Sopenharmony_ci    desc.Format = dest_surface->desc.Format;
1132bf215546Sopenharmony_ci    desc.Usage = D3DUSAGE_RENDERTARGET;
1133bf215546Sopenharmony_ci    hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0,
1134bf215546Sopenharmony_ci                          0, 0, &desc, &temp_surface);
1135bf215546Sopenharmony_ci    pipe_resource_reference(&temp_resource, NULL);
1136bf215546Sopenharmony_ci    if (FAILED(hr)) {
1137bf215546Sopenharmony_ci        DBG("Failed to create temp FrontBuffer surface.\n");
1138bf215546Sopenharmony_ci        return hr;
1139bf215546Sopenharmony_ci    }
1140bf215546Sopenharmony_ci
1141bf215546Sopenharmony_ci    ID3DPresent_FrontBufferCopy(This->present, temp_handle);
1142bf215546Sopenharmony_ci
1143bf215546Sopenharmony_ci    NineSurface9_CopyDefaultToMem(dest_surface, temp_surface);
1144bf215546Sopenharmony_ci
1145bf215546Sopenharmony_ci    ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
1146bf215546Sopenharmony_ci    NineUnknown_Destroy(NineUnknown(temp_surface));
1147bf215546Sopenharmony_ci
1148bf215546Sopenharmony_ci    return D3D_OK;
1149bf215546Sopenharmony_ci}
1150bf215546Sopenharmony_ci
1151bf215546Sopenharmony_ciHRESULT NINE_WINAPI
1152bf215546Sopenharmony_ciNineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
1153bf215546Sopenharmony_ci                              UINT iBackBuffer,
1154bf215546Sopenharmony_ci                              D3DBACKBUFFER_TYPE Type,
1155bf215546Sopenharmony_ci                              IDirect3DSurface9 **ppBackBuffer )
1156bf215546Sopenharmony_ci{
1157bf215546Sopenharmony_ci    DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
1158bf215546Sopenharmony_ci        This, iBackBuffer, Type, ppBackBuffer);
1159bf215546Sopenharmony_ci    (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
1160bf215546Sopenharmony_ci    /* don't touch ppBackBuffer on error */
1161bf215546Sopenharmony_ci    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
1162bf215546Sopenharmony_ci    user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
1163bf215546Sopenharmony_ci
1164bf215546Sopenharmony_ci    NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
1165bf215546Sopenharmony_ci    *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
1166bf215546Sopenharmony_ci    return D3D_OK;
1167bf215546Sopenharmony_ci}
1168bf215546Sopenharmony_ci
1169bf215546Sopenharmony_ciHRESULT NINE_WINAPI
1170bf215546Sopenharmony_ciNineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
1171bf215546Sopenharmony_ci                                D3DRASTER_STATUS *pRasterStatus )
1172bf215546Sopenharmony_ci{
1173bf215546Sopenharmony_ci    DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
1174bf215546Sopenharmony_ci        This, pRasterStatus);
1175bf215546Sopenharmony_ci    user_assert(pRasterStatus != NULL, E_POINTER);
1176bf215546Sopenharmony_ci    return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
1177bf215546Sopenharmony_ci}
1178bf215546Sopenharmony_ci
1179bf215546Sopenharmony_ciHRESULT NINE_WINAPI
1180bf215546Sopenharmony_ciNineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
1181bf215546Sopenharmony_ci                               D3DDISPLAYMODE *pMode )
1182bf215546Sopenharmony_ci{
1183bf215546Sopenharmony_ci    D3DDISPLAYMODEEX mode;
1184bf215546Sopenharmony_ci    D3DDISPLAYROTATION rot;
1185bf215546Sopenharmony_ci    HRESULT hr;
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ci    DBG("GetDisplayMode: This=%p pMode=%p\n",
1188bf215546Sopenharmony_ci        This, pMode);
1189bf215546Sopenharmony_ci    user_assert(pMode != NULL, E_POINTER);
1190bf215546Sopenharmony_ci
1191bf215546Sopenharmony_ci    hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
1192bf215546Sopenharmony_ci    if (SUCCEEDED(hr)) {
1193bf215546Sopenharmony_ci        pMode->Width = mode.Width;
1194bf215546Sopenharmony_ci        pMode->Height = mode.Height;
1195bf215546Sopenharmony_ci        pMode->RefreshRate = mode.RefreshRate;
1196bf215546Sopenharmony_ci        pMode->Format = mode.Format;
1197bf215546Sopenharmony_ci    }
1198bf215546Sopenharmony_ci    return hr;
1199bf215546Sopenharmony_ci}
1200bf215546Sopenharmony_ci
1201bf215546Sopenharmony_ciHRESULT NINE_WINAPI
1202bf215546Sopenharmony_ciNineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
1203bf215546Sopenharmony_ci                                     D3DPRESENT_PARAMETERS *pPresentationParameters )
1204bf215546Sopenharmony_ci{
1205bf215546Sopenharmony_ci    DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
1206bf215546Sopenharmony_ci        This, pPresentationParameters);
1207bf215546Sopenharmony_ci    user_assert(pPresentationParameters != NULL, E_POINTER);
1208bf215546Sopenharmony_ci    *pPresentationParameters = This->params;
1209bf215546Sopenharmony_ci    return D3D_OK;
1210bf215546Sopenharmony_ci}
1211bf215546Sopenharmony_ci
1212bf215546Sopenharmony_ciIDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
1213bf215546Sopenharmony_ci    (void *)NineUnknown_QueryInterface,
1214bf215546Sopenharmony_ci    (void *)NineUnknown_AddRef,
1215bf215546Sopenharmony_ci    (void *)NineUnknown_Release,
1216bf215546Sopenharmony_ci    (void *)NineSwapChain9_Present,
1217bf215546Sopenharmony_ci    (void *)NineSwapChain9_GetFrontBufferData,
1218bf215546Sopenharmony_ci    (void *)NineSwapChain9_GetBackBuffer,
1219bf215546Sopenharmony_ci    (void *)NineSwapChain9_GetRasterStatus,
1220bf215546Sopenharmony_ci    (void *)NineSwapChain9_GetDisplayMode,
1221bf215546Sopenharmony_ci    (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
1222bf215546Sopenharmony_ci    (void *)NineSwapChain9_GetPresentParameters
1223bf215546Sopenharmony_ci};
1224bf215546Sopenharmony_ci
1225bf215546Sopenharmony_cistatic const GUID *NineSwapChain9_IIDs[] = {
1226bf215546Sopenharmony_ci    &IID_IDirect3DSwapChain9,
1227bf215546Sopenharmony_ci    &IID_IUnknown,
1228bf215546Sopenharmony_ci    NULL
1229bf215546Sopenharmony_ci};
1230bf215546Sopenharmony_ci
1231bf215546Sopenharmony_ciHRESULT
1232bf215546Sopenharmony_ciNineSwapChain9_new( struct NineDevice9 *pDevice,
1233bf215546Sopenharmony_ci                    BOOL implicit,
1234bf215546Sopenharmony_ci                    ID3DPresent *pPresent,
1235bf215546Sopenharmony_ci                    D3DPRESENT_PARAMETERS *pPresentationParameters,
1236bf215546Sopenharmony_ci                    struct d3dadapter9_context *pCTX,
1237bf215546Sopenharmony_ci                    HWND hFocusWindow,
1238bf215546Sopenharmony_ci                    struct NineSwapChain9 **ppOut )
1239bf215546Sopenharmony_ci{
1240bf215546Sopenharmony_ci    NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
1241bf215546Sopenharmony_ci                          implicit, pPresent, pPresentationParameters,
1242bf215546Sopenharmony_ci                          pCTX, hFocusWindow, NULL);
1243bf215546Sopenharmony_ci}
1244bf215546Sopenharmony_ci
1245bf215546Sopenharmony_ciBOOL
1246bf215546Sopenharmony_ciNineSwapChain9_GetOccluded( struct NineSwapChain9 *This )
1247bf215546Sopenharmony_ci{
1248bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 0) {
1249bf215546Sopenharmony_ci        return ID3DPresent_GetWindowOccluded(This->present);
1250bf215546Sopenharmony_ci    }
1251bf215546Sopenharmony_ci
1252bf215546Sopenharmony_ci    return FALSE;
1253bf215546Sopenharmony_ci}
1254bf215546Sopenharmony_ci
1255bf215546Sopenharmony_ciBOOL
1256bf215546Sopenharmony_ciNineSwapChain9_ResolutionMismatch( struct NineSwapChain9 *This )
1257bf215546Sopenharmony_ci{
1258bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 1) {
1259bf215546Sopenharmony_ci        return ID3DPresent_ResolutionMismatch(This->present);
1260bf215546Sopenharmony_ci    }
1261bf215546Sopenharmony_ci
1262bf215546Sopenharmony_ci    return FALSE;
1263bf215546Sopenharmony_ci}
1264bf215546Sopenharmony_ci
1265bf215546Sopenharmony_ciHANDLE
1266bf215546Sopenharmony_ciNineSwapChain9_CreateThread( struct NineSwapChain9 *This,
1267bf215546Sopenharmony_ci                                 void *pFuncAddress,
1268bf215546Sopenharmony_ci                                 void *pParam )
1269bf215546Sopenharmony_ci{
1270bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 1) {
1271bf215546Sopenharmony_ci        return ID3DPresent_CreateThread(This->present, pFuncAddress, pParam);
1272bf215546Sopenharmony_ci    }
1273bf215546Sopenharmony_ci
1274bf215546Sopenharmony_ci    return NULL;
1275bf215546Sopenharmony_ci}
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_civoid
1278bf215546Sopenharmony_ciNineSwapChain9_WaitForThread( struct NineSwapChain9 *This,
1279bf215546Sopenharmony_ci                                  HANDLE thread )
1280bf215546Sopenharmony_ci{
1281bf215546Sopenharmony_ci    if (This->base.device->minor_version_num > 1) {
1282bf215546Sopenharmony_ci        (void) ID3DPresent_WaitForThread(This->present, thread);
1283bf215546Sopenharmony_ci    }
1284bf215546Sopenharmony_ci}
1285bf215546Sopenharmony_ci
1286bf215546Sopenharmony_cistatic int
1287bf215546Sopenharmony_ciNineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
1288bf215546Sopenharmony_ci                                            D3DPRESENT_PARAMETERS *pParams )
1289bf215546Sopenharmony_ci{
1290bf215546Sopenharmony_ci    int count = pParams->BackBufferCount;
1291bf215546Sopenharmony_ci
1292bf215546Sopenharmony_ci    /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
1293bf215546Sopenharmony_ci     * Here we don't get back the initial content of the screen. To emulate the behaviour
1294bf215546Sopenharmony_ci     * we allocate an additional buffer */
1295bf215546Sopenharmony_ci    if (pParams->SwapEffect != D3DSWAPEFFECT_COPY)
1296bf215546Sopenharmony_ci        count++;
1297bf215546Sopenharmony_ci    /* With DISCARD, as there is no guarantee about the buffer contents, we can use
1298bf215546Sopenharmony_ci     * an arbitrary number of buffers */
1299bf215546Sopenharmony_ci    if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) {
1300bf215546Sopenharmony_ci        /* thread_submit's can have maximum count or This->actx->throttling_value + 1
1301bf215546Sopenharmony_ci         * frames in flight being rendered and not shown.
1302bf215546Sopenharmony_ci         * Do not let count decrease that number */
1303bf215546Sopenharmony_ci        if (This->actx->thread_submit && count < This->desired_fences)
1304bf215546Sopenharmony_ci            count = This->desired_fences;
1305bf215546Sopenharmony_ci        /* When we enable AllowDISCARDDelayedRelease, we must ensure
1306bf215546Sopenharmony_ci         * to have at least 4 buffers to meet INTERVAL_IMMEDIATE,
1307bf215546Sopenharmony_ci         * since the display server/compositor can hold 3 buffers
1308bf215546Sopenharmony_ci         * without releasing them:
1309bf215546Sopenharmony_ci         * . Buffer on screen.
1310bf215546Sopenharmony_ci         * . Buffer scheduled kernel side to be next on screen.
1311bf215546Sopenharmony_ci         * . Last buffer sent. */
1312bf215546Sopenharmony_ci        if (This->base.device->minor_version_num > 2 &&
1313bf215546Sopenharmony_ci            This->actx->discard_delayed_release &&
1314bf215546Sopenharmony_ci            pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE) {
1315bf215546Sopenharmony_ci            if (This->actx->thread_submit && count < 4)
1316bf215546Sopenharmony_ci                count = 4;
1317bf215546Sopenharmony_ci            /* When thread_submit is not used, 5 buffers are actually needed,
1318bf215546Sopenharmony_ci             * because in case a pageflip is missed because rendering wasn't finished,
1319bf215546Sopenharmony_ci             * the Xserver will hold 4 buffers. */
1320bf215546Sopenharmony_ci            else if (!This->actx->thread_submit && count < 5)
1321bf215546Sopenharmony_ci                count = 5;
1322bf215546Sopenharmony_ci            /* Somehow this cases needs 5 with thread_submit, or else you get a small performance hit */
1323bf215546Sopenharmony_ci            if (This->actx->tearfree_discard && count < 5)
1324bf215546Sopenharmony_ci                count = 5;
1325bf215546Sopenharmony_ci        }
1326bf215546Sopenharmony_ci    }
1327bf215546Sopenharmony_ci
1328bf215546Sopenharmony_ci    return count;
1329bf215546Sopenharmony_ci}
1330