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