Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2011 Joakim Sindholt <opensource@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->pipe = NineDevice9_GetPipe(This->base.device);
  63.     This->cso = NineDevice9_GetCSO(This->base.device);
  64.     This->implicit = implicit;
  65.     This->actx = pCTX;
  66.     This->present = pPresent;
  67.     This->mode = NULL;
  68.  
  69.     ID3DPresent_AddRef(pPresent);
  70.  
  71.     if (!pPresentationParameters->hDeviceWindow)
  72.         pPresentationParameters->hDeviceWindow = hFocusWindow;
  73.  
  74.     This->rendering_done = FALSE;
  75.     This->pool = NULL;
  76.     return NineSwapChain9_Resize(This, pPresentationParameters, mode);
  77. }
  78.  
  79. static D3DWindowBuffer *
  80. D3DWindowBuffer_create(struct NineSwapChain9 *This,
  81.                        struct pipe_resource *resource,
  82.                        int depth)
  83. {
  84.     D3DWindowBuffer *ret;
  85.     struct winsys_handle whandle;
  86.     int stride, dmaBufFd;
  87.  
  88.     memset(&whandle, 0, sizeof(whandle));
  89.     whandle.type = DRM_API_HANDLE_TYPE_FD;
  90.     This->screen->resource_get_handle(This->screen, resource, &whandle);
  91.     stride = whandle.stride;
  92.     dmaBufFd = whandle.handle;
  93.     ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
  94.                                              dmaBufFd,
  95.                                              resource->width0,
  96.                                              resource->height0,
  97.                                              stride,
  98.                                              depth,
  99.                                              32,
  100.                                              &ret);
  101.     return ret;
  102. }
  103.  
  104. HRESULT
  105. NineSwapChain9_Resize( struct NineSwapChain9 *This,
  106.                        D3DPRESENT_PARAMETERS *pParams,
  107.                        D3DDISPLAYMODEEX *mode )
  108. {
  109.     struct NineDevice9 *pDevice = This->base.device;
  110.     struct NineSurface9 **bufs;
  111.     D3DSURFACE_DESC desc;
  112.     HRESULT hr;
  113.     struct pipe_resource *resource, tmplt;
  114.     enum pipe_format pf;
  115.     BOOL has_present_buffers = FALSE;
  116.     int depth;
  117.     unsigned i, oldBufferCount, newBufferCount;
  118.  
  119.     DBG("This=%p pParams=%p\n", This, pParams);
  120.     user_assert(pParams != NULL, E_POINTER);
  121.  
  122.     DBG("pParams(%p):\n"
  123.         "BackBufferWidth: %u\n"
  124.         "BackBufferHeight: %u\n"
  125.         "BackBufferFormat: %s\n"
  126.         "BackBufferCount: %u\n"
  127.         "MultiSampleType: %u\n"
  128.         "MultiSampleQuality: %u\n"
  129.         "SwapEffect: %u\n"
  130.         "hDeviceWindow: %p\n"
  131.         "Windowed: %i\n"
  132.         "EnableAutoDepthStencil: %i\n"
  133.         "AutoDepthStencilFormat: %s\n"
  134.         "Flags: %s\n"
  135.         "FullScreen_RefreshRateInHz: %u\n"
  136.         "PresentationInterval: %x\n", pParams,
  137.         pParams->BackBufferWidth, pParams->BackBufferHeight,
  138.         d3dformat_to_string(pParams->BackBufferFormat),
  139.         pParams->BackBufferCount,
  140.         pParams->MultiSampleType, pParams->MultiSampleQuality,
  141.         pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
  142.         pParams->EnableAutoDepthStencil,
  143.         d3dformat_to_string(pParams->AutoDepthStencilFormat),
  144.         nine_D3DPRESENTFLAG_to_str(pParams->Flags),
  145.         pParams->FullScreen_RefreshRateInHz,
  146.         pParams->PresentationInterval);
  147.  
  148.     if (pParams->SwapEffect == D3DSWAPEFFECT_COPY &&
  149.         pParams->BackBufferCount > 1) {
  150.         pParams->BackBufferCount = 1;
  151.     }
  152.  
  153.     if (pParams->BackBufferCount > 3) {
  154.         pParams->BackBufferCount = 3;
  155.     }
  156.  
  157.     if (pParams->BackBufferCount == 0) {
  158.         pParams->BackBufferCount = 1;
  159.     }
  160.  
  161.     if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
  162.         pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
  163.     }
  164.  
  165.     This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
  166.     /* +1 because we add the fence of the current buffer before popping an old one */
  167.     if (This->desired_fences > DRI_SWAP_FENCES_MAX)
  168.         This->desired_fences = DRI_SWAP_FENCES_MAX;
  169.  
  170.     if (This->actx->vblank_mode == 0)
  171.         pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  172.     else if (This->actx->vblank_mode == 3)
  173.         pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  174.  
  175.     if (mode && This->mode) {
  176.         *(This->mode) = *mode;
  177.     } else if (mode) {
  178.         This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
  179.         memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
  180.     } else {
  181.         free(This->mode);
  182.         This->mode = NULL;
  183.     }
  184.  
  185.     /* Note: It is the role of the backend to fill if necessary
  186.      * BackBufferWidth and BackBufferHeight */
  187.     ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
  188.  
  189.     /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
  190.      * Here we don't get back the initial content of the screen. To emulate the behaviour
  191.      * we allocate an additional buffer */
  192.     oldBufferCount = This->params.BackBufferCount ?
  193.                      (This->params.BackBufferCount +
  194.                       (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0;
  195.     newBufferCount = pParams->BackBufferCount +
  196.                      (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
  197.  
  198.     pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat,
  199.                                      PIPE_TEXTURE_2D, pParams->MultiSampleType,
  200.                                      PIPE_BIND_RENDER_TARGET, FALSE);
  201.  
  202.     if (This->actx->linear_framebuffer ||
  203.         (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
  204.         pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
  205.         pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
  206.         pParams->MultiSampleType >= 2 ||
  207.         (This->actx->ref && This->actx->ref == This->screen))
  208.         has_present_buffers = TRUE;
  209.  
  210.     /* Note: the buffer depth has to match the window depth.
  211.      * In practice, ARGB buffers can be used with windows
  212.      * of depth 24. Windows of depth 32 are extremely rare.
  213.      * So even if the buffer is ARGB, say it is depth 24.
  214.      * It is common practice, for example that's how
  215.      * glamor implements depth 24.
  216.      * TODO: handle windows with other depths. Not possible in the short term.
  217.      * For example 16 bits.*/
  218.     depth = 24;
  219.  
  220.     tmplt.target = PIPE_TEXTURE_2D;
  221.     tmplt.width0 = pParams->BackBufferWidth;
  222.     tmplt.height0 = pParams->BackBufferHeight;
  223.     tmplt.depth0 = 1;
  224.     tmplt.last_level = 0;
  225.     tmplt.array_size = 1;
  226.     tmplt.usage = PIPE_USAGE_DEFAULT;
  227.     tmplt.flags = 0;
  228.  
  229.     desc.Type = D3DRTYPE_SURFACE;
  230.     desc.Pool = D3DPOOL_DEFAULT;
  231.     desc.MultiSampleType = pParams->MultiSampleType;
  232.     desc.MultiSampleQuality = 0;
  233.     desc.Width = pParams->BackBufferWidth;
  234.     desc.Height = pParams->BackBufferHeight;
  235.  
  236.     if (This->pool) {
  237.         _mesa_threadpool_destroy(This->pool);
  238.         This->pool = NULL;
  239.     }
  240.     This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
  241.     if (This->enable_threadpool)
  242.         This->pool = _mesa_threadpool_create();
  243.     if (!This->pool)
  244.         This->enable_threadpool = FALSE;
  245.  
  246.     This->tasks = REALLOC(This->tasks,
  247.                           oldBufferCount * sizeof(struct threadpool_task *),
  248.                           newBufferCount * sizeof(struct threadpool_task *));
  249.     memset(This->tasks, 0, newBufferCount * sizeof(struct threadpool_task *));
  250.  
  251.     for (i = 0; i < oldBufferCount; i++) {
  252.         ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
  253.         This->present_handles[i] = NULL;
  254.         if (This->present_buffers)
  255.             pipe_resource_reference(&(This->present_buffers[i]), NULL);
  256.     }
  257.  
  258.     if (!has_present_buffers && This->present_buffers) {
  259.         FREE(This->present_buffers);
  260.         This->present_buffers = NULL;
  261.     }
  262.  
  263.     if (newBufferCount != oldBufferCount) {
  264.         for (i = newBufferCount; i < oldBufferCount;
  265.              ++i)
  266.             NineUnknown_Detach(NineUnknown(This->buffers[i]));
  267.  
  268.         bufs = REALLOC(This->buffers,
  269.                        oldBufferCount * sizeof(This->buffers[0]),
  270.                        newBufferCount * sizeof(This->buffers[0]));
  271.         if (!bufs)
  272.             return E_OUTOFMEMORY;
  273.         This->buffers = bufs;
  274.         This->present_handles = REALLOC(This->present_handles,
  275.                                         oldBufferCount * sizeof(D3DWindowBuffer *),
  276.                                         newBufferCount * sizeof(D3DWindowBuffer *));
  277.         for (i = oldBufferCount; i < newBufferCount; ++i) {
  278.             This->buffers[i] = NULL;
  279.             This->present_handles[i] = NULL;
  280.         }
  281.     }
  282.  
  283.     if (has_present_buffers &&
  284.         (newBufferCount != oldBufferCount || !This->present_buffers)) {
  285.         This->present_buffers = REALLOC(This->present_buffers,
  286.                                         This->present_buffers == NULL ? 0 :
  287.                                         oldBufferCount * sizeof(struct pipe_resource *),
  288.                                         newBufferCount * sizeof(struct pipe_resource *));
  289.         memset(This->present_buffers, 0, newBufferCount * sizeof(struct pipe_resource *));
  290.     }
  291.  
  292.     for (i = 0; i < newBufferCount; ++i) {
  293.         tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
  294.                      PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET;
  295.         tmplt.nr_samples = pParams->MultiSampleType;
  296.         if (!has_present_buffers)
  297.             tmplt.bind |= PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
  298.         tmplt.format = d3d9_to_pipe_format_checked(This->screen,
  299.                                                    pParams->BackBufferFormat,
  300.                                                    PIPE_TEXTURE_2D,
  301.                                                    tmplt.nr_samples,
  302.                                                    tmplt.bind, FALSE);
  303.         if (tmplt.format == PIPE_FORMAT_NONE)
  304.             return D3DERR_INVALIDCALL;
  305.         resource = This->screen->resource_create(This->screen, &tmplt);
  306.         if (!resource) {
  307.             DBG("Failed to create pipe_resource.\n");
  308.             return D3DERR_OUTOFVIDEOMEMORY;
  309.         }
  310.         if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
  311.             resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
  312.         if (This->buffers[i]) {
  313.             NineSurface9_SetResourceResize(This->buffers[i], resource);
  314.             if (has_present_buffers)
  315.                 pipe_resource_reference(&resource, NULL);
  316.         } else {
  317.             desc.Format = pParams->BackBufferFormat;
  318.             desc.Usage = D3DUSAGE_RENDERTARGET;
  319.             hr = NineSurface9_new(pDevice, NineUnknown(This), resource, NULL, 0,
  320.                                   0, 0, &desc, &This->buffers[i]);
  321.             if (has_present_buffers)
  322.                 pipe_resource_reference(&resource, NULL);
  323.             if (FAILED(hr)) {
  324.                 DBG("Failed to create RT surface.\n");
  325.                 return hr;
  326.             }
  327.             This->buffers[i]->base.base.forward = FALSE;
  328.         }
  329.         if (has_present_buffers) {
  330.             tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
  331.             tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
  332.             tmplt.nr_samples = 0;
  333.             if (This->actx->linear_framebuffer)
  334.                 tmplt.bind |= PIPE_BIND_LINEAR;
  335.             if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
  336.                 tmplt.bind |= PIPE_BIND_RENDER_TARGET;
  337.             resource = This->screen->resource_create(This->screen, &tmplt);
  338.             pipe_resource_reference(&(This->present_buffers[i]), resource);
  339.         }
  340.         This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth);
  341.         pipe_resource_reference(&resource, NULL);
  342.     }
  343.     if (pParams->EnableAutoDepthStencil) {
  344.         tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat);
  345.         /* Checking the d3d9 depth format for texture support indicates the app if it can use
  346.          * the format for shadow mapping or texturing. If the check returns true, then the app
  347.          * is allowed to use this functionnality, so try first to create the buffer
  348.          * with PIPE_BIND_SAMPLER_VIEW. If the format can't be created with it, try without.
  349.          * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support
  350.          * would fail too, so we are fine. */
  351.         tmplt.bind |= PIPE_BIND_SAMPLER_VIEW;
  352.         tmplt.nr_samples = pParams->MultiSampleType;
  353.         tmplt.format = d3d9_to_pipe_format_checked(This->screen,
  354.                                                    pParams->AutoDepthStencilFormat,
  355.                                                    PIPE_TEXTURE_2D,
  356.                                                    tmplt.nr_samples,
  357.                                                    tmplt.bind,
  358.                                                    FALSE);
  359.         if (tmplt.format == PIPE_FORMAT_NONE) {
  360.             tmplt.bind &= ~PIPE_BIND_SAMPLER_VIEW;
  361.             tmplt.format = d3d9_to_pipe_format_checked(This->screen,
  362.                                                        pParams->AutoDepthStencilFormat,
  363.                                                        PIPE_TEXTURE_2D,
  364.                                                        tmplt.nr_samples,
  365.                                                        tmplt.bind,
  366.                                                        FALSE);
  367.         }
  368.  
  369.         if (tmplt.format == PIPE_FORMAT_NONE)
  370.             return D3DERR_INVALIDCALL;
  371.  
  372.         resource = This->screen->resource_create(This->screen, &tmplt);
  373.         if (!resource) {
  374.             DBG("Failed to create pipe_resource for depth buffer.\n");
  375.             return D3DERR_OUTOFVIDEOMEMORY;
  376.         }
  377.         if (This->zsbuf) {
  378.             NineSurface9_SetResourceResize(This->zsbuf, resource);
  379.             pipe_resource_reference(&resource, NULL);
  380.         } else {
  381.             /* XXX wine thinks the container of this should be the device */
  382.             desc.Format = pParams->AutoDepthStencilFormat;
  383.             desc.Usage = D3DUSAGE_DEPTHSTENCIL;
  384.             hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, NULL, 0,
  385.                                   0, 0, &desc, &This->zsbuf);
  386.             pipe_resource_reference(&resource, NULL);
  387.             if (FAILED(hr)) {
  388.                 DBG("Failed to create ZS surface.\n");
  389.                 return hr;
  390.             }
  391.             This->zsbuf->base.base.forward = FALSE;
  392.         }
  393.     }
  394.  
  395.     This->params = *pParams;
  396.  
  397.     return D3D_OK;
  398. }
  399.  
  400. /* Throttling: code adapted from the dri state tracker */
  401.  
  402. /**
  403.  * swap_fences_pop_front - pull a fence from the throttle queue
  404.  *
  405.  * If the throttle queue is filled to the desired number of fences,
  406.  * pull fences off the queue until the number is less than the desired
  407.  * number of fences, and return the last fence pulled.
  408.  */
  409. static struct pipe_fence_handle *
  410. swap_fences_pop_front(struct NineSwapChain9 *This)
  411. {
  412.     struct pipe_screen *screen = This->screen;
  413.     struct pipe_fence_handle *fence = NULL;
  414.  
  415.     if (This->desired_fences == 0)
  416.         return NULL;
  417.  
  418.     if (This->cur_fences >= This->desired_fences) {
  419.         screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
  420.         screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
  421.         This->tail &= DRI_SWAP_FENCES_MASK;
  422.         --This->cur_fences;
  423.     }
  424.     return fence;
  425. }
  426.  
  427.  
  428. /**
  429.  * swap_fences_see_front - same than swap_fences_pop_front without
  430.  * pulling
  431.  *
  432.  */
  433.  
  434. static struct pipe_fence_handle *
  435. swap_fences_see_front(struct NineSwapChain9 *This)
  436. {
  437.     struct pipe_screen *screen = This->screen;
  438.     struct pipe_fence_handle *fence = NULL;
  439.  
  440.     if (This->desired_fences == 0)
  441.         return NULL;
  442.  
  443.     if (This->cur_fences >= This->desired_fences) {
  444.         screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
  445.     }
  446.     return fence;
  447. }
  448.  
  449.  
  450. /**
  451.  * swap_fences_push_back - push a fence onto the throttle queue at the back
  452.  *
  453.  * push a fence onto the throttle queue and pull fences of the queue
  454.  * so that the desired number of fences are on the queue.
  455.  */
  456. static void
  457. swap_fences_push_back(struct NineSwapChain9 *This,
  458.                       struct pipe_fence_handle *fence)
  459. {
  460.     struct pipe_screen *screen = This->screen;
  461.  
  462.     if (!fence || This->desired_fences == 0)
  463.         return;
  464.  
  465.     while(This->cur_fences == This->desired_fences)
  466.         swap_fences_pop_front(This);
  467.  
  468.     This->cur_fences++;
  469.     screen->fence_reference(screen, &This->swap_fences[This->head++],
  470.                             fence);
  471.     This->head &= DRI_SWAP_FENCES_MASK;
  472. }
  473.  
  474.  
  475. /**
  476.  * swap_fences_unref - empty the throttle queue
  477.  *
  478.  * pulls fences of the throttle queue until it is empty.
  479.  */
  480. static void
  481. swap_fences_unref(struct NineSwapChain9 *This)
  482. {
  483.     struct pipe_screen *screen = This->screen;
  484.  
  485.     while(This->cur_fences) {
  486.         screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
  487.         This->tail &= DRI_SWAP_FENCES_MASK;
  488.         --This->cur_fences;
  489.     }
  490. }
  491.  
  492. void
  493. NineSwapChain9_dtor( struct NineSwapChain9 *This )
  494. {
  495.     unsigned i;
  496.  
  497.     DBG("This=%p\n", This);
  498.  
  499.     if (This->pool)
  500.         _mesa_threadpool_destroy(This->pool);
  501.  
  502.     if (This->buffers) {
  503.         for (i = 0; i < This->params.BackBufferCount; i++) {
  504.             NineUnknown_Release(NineUnknown(This->buffers[i]));
  505.             ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
  506.             if (This->present_buffers)
  507.                 pipe_resource_reference(&(This->present_buffers[i]), NULL);
  508.         }
  509.         FREE(This->buffers);
  510.         FREE(This->present_buffers);
  511.     }
  512.     if (This->zsbuf)
  513.         NineUnknown_Destroy(NineUnknown(This->zsbuf));
  514.  
  515.     if (This->present)
  516.         ID3DPresent_Release(This->present);
  517.  
  518.     swap_fences_unref(This);
  519.     NineUnknown_dtor(&This->base);
  520. }
  521.  
  522. static void
  523. create_present_buffer( struct NineSwapChain9 *This,
  524.                        unsigned int width, unsigned int height,
  525.                        struct pipe_resource **resource,
  526.                        D3DWindowBuffer **present_handle)
  527. {
  528.     struct pipe_resource tmplt;
  529.  
  530.     tmplt.target = PIPE_TEXTURE_2D;
  531.     tmplt.width0 = width;
  532.     tmplt.height0 = height;
  533.     tmplt.depth0 = 1;
  534.     tmplt.last_level = 0;
  535.     tmplt.array_size = 1;
  536.     tmplt.usage = PIPE_USAGE_DEFAULT;
  537.     tmplt.flags = 0;
  538.     tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
  539.     tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
  540.                  PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET |
  541.                  PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
  542.     tmplt.nr_samples = 0;
  543.     if (This->actx->linear_framebuffer)
  544.         tmplt.bind |= PIPE_BIND_LINEAR;
  545.     *resource = This->screen->resource_create(This->screen, &tmplt);
  546.  
  547.     *present_handle = D3DWindowBuffer_create(This, *resource, 24);
  548. }
  549.  
  550. static void
  551. handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
  552. {
  553.     struct NineDevice9 *device = This->base.device;
  554.     struct pipe_blit_info blit;
  555.  
  556.     if (device->cursor.software && device->cursor.visible && device->cursor.w) {
  557.         memset(&blit, 0, sizeof(blit));
  558.         blit.src.resource = device->cursor.image;
  559.         blit.src.level = 0;
  560.         blit.src.format = device->cursor.image->format;
  561.         blit.src.box.x = 0;
  562.         blit.src.box.y = 0;
  563.         blit.src.box.z = 0;
  564.         blit.src.box.depth = 1;
  565.         blit.src.box.width = device->cursor.w;
  566.         blit.src.box.height = device->cursor.h;
  567.  
  568.         blit.dst.resource = resource;
  569.         blit.dst.level = 0;
  570.         blit.dst.format = resource->format;
  571.         blit.dst.box.z = 0;
  572.         blit.dst.box.depth = 1;
  573.  
  574.         blit.mask = PIPE_MASK_RGBA;
  575.         blit.filter = PIPE_TEX_FILTER_NEAREST;
  576.         blit.scissor_enable = FALSE;
  577.  
  578.         ID3DPresent_GetCursorPos(This->present, &device->cursor.pos);
  579.  
  580.         /* NOTE: blit messes up when box.x + box.width < 0, fix driver */
  581.         blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
  582.         blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
  583.         blit.dst.box.width = blit.src.box.width;
  584.         blit.dst.box.height = blit.src.box.height;
  585.  
  586.         DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
  587.             blit.src.box.width, blit.src.box.height,
  588.             blit.dst.box.x, blit.dst.box.y);
  589.  
  590.         This->pipe->blit(This->pipe, &blit);
  591.     }
  592.  
  593.     if (device->hud && resource) {
  594.         hud_draw(device->hud, resource); /* XXX: no offset */
  595.         /* HUD doesn't clobber stipple */
  596.         NineDevice9_RestoreNonCSOState(device, ~0x2);
  597.     }
  598. }
  599.  
  600. struct end_present_struct {
  601.     struct pipe_screen *screen;
  602.     struct pipe_fence_handle *fence_to_wait;
  603.     ID3DPresent *present;
  604.     D3DWindowBuffer *present_handle;
  605.     HWND hDestWindowOverride;
  606. };
  607.  
  608. static void work_present(void *data)
  609. {
  610.     struct end_present_struct *work = data;
  611.     if (work->fence_to_wait) {
  612.         (void) work->screen->fence_finish(work->screen, work->fence_to_wait, PIPE_TIMEOUT_INFINITE);
  613.         work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL);
  614.     }
  615.     ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0);
  616.     free(work);
  617. }
  618.  
  619. static void pend_present(struct NineSwapChain9 *This,
  620.                          HWND hDestWindowOverride)
  621. {
  622.     struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct));
  623.  
  624.     work->screen = This->screen;
  625.     work->fence_to_wait = swap_fences_pop_front(This);
  626.     work->present = This->present;
  627.     work->present_handle = This->present_handles[0];
  628.     work->hDestWindowOverride = hDestWindowOverride;
  629.     This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work);
  630.  
  631.     return;
  632. }
  633.  
  634. static INLINE HRESULT
  635. present( struct NineSwapChain9 *This,
  636.          const RECT *pSourceRect,
  637.          const RECT *pDestRect,
  638.          HWND hDestWindowOverride,
  639.          const RGNDATA *pDirtyRegion,
  640.          DWORD dwFlags )
  641. {
  642.     struct pipe_resource *resource;
  643.     struct pipe_fence_handle *fence;
  644.     HRESULT hr;
  645.     struct pipe_blit_info blit;
  646.  
  647.     DBG("present: This=%p pSourceRect=%p pDestRect=%p "
  648.         "pDirtyRegion=%p hDestWindowOverride=%p"
  649.         "dwFlags=%d resource=%p\n",
  650.         This, pSourceRect, pDestRect, pDirtyRegion,
  651.         hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
  652.  
  653.     if (pSourceRect)
  654.         DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
  655.             pSourceRect->left, pSourceRect->right,
  656.             pSourceRect->top, pSourceRect->bottom);
  657.     if (pDestRect)
  658.         DBG("pDestRect = (%u..%u)x(%u..%u)\n",
  659.             pDestRect->left, pDestRect->right,
  660.             pDestRect->top, pDestRect->bottom);
  661.  
  662.     /* TODO: in the case the source and destination rect have different size:
  663.      * We need to allocate a new buffer, and do a blit to it to resize.
  664.      * We can't use the present_buffer for that since when we created it,
  665.      * we couldn't guess which size would have been needed.
  666.      * If pDestRect or pSourceRect is null, we have to check the sizes
  667.      * from the source size, and the destination window size.
  668.      * In this case, either resize rngdata, or pass NULL instead
  669.      */
  670.     /* Note: This->buffers[0]->level should always be 0 */
  671.  
  672.     if (This->rendering_done)
  673.         goto bypass_rendering;
  674.  
  675.     resource = This->buffers[0]->base.resource;
  676.  
  677.     if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
  678.         handle_draw_cursor_and_hud(This, resource);
  679.  
  680.     if (This->present_buffers) {
  681.         memset(&blit, 0, sizeof(blit));
  682.         blit.src.resource = resource;
  683.         blit.src.level = 0;
  684.         blit.src.format = resource->format;
  685.         blit.src.box.z = 0;
  686.         blit.src.box.depth = 1;
  687.         blit.src.box.x = 0;
  688.         blit.src.box.y = 0;
  689.         blit.src.box.width = resource->width0;
  690.         blit.src.box.height = resource->height0;
  691.  
  692.         resource = This->present_buffers[0];
  693.  
  694.         blit.dst.resource = resource;
  695.         blit.dst.level = 0;
  696.         blit.dst.format = resource->format;
  697.         blit.dst.box.z = 0;
  698.         blit.dst.box.depth = 1;
  699.         blit.dst.box.x = 0;
  700.         blit.dst.box.y = 0;
  701.         blit.dst.box.width = resource->width0;
  702.         blit.dst.box.height = resource->height0;
  703.  
  704.         blit.mask = PIPE_MASK_RGBA;
  705.         blit.filter = PIPE_TEX_FILTER_NEAREST;
  706.         blit.scissor_enable = FALSE;
  707.  
  708.         This->pipe->blit(This->pipe, &blit);
  709.     }
  710.  
  711.     if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
  712.         handle_draw_cursor_and_hud(This, resource);
  713.  
  714.     fence = NULL;
  715.     This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
  716.     if (fence) {
  717.         swap_fences_push_back(This, fence);
  718.         This->screen->fence_reference(This->screen, &fence, NULL);
  719.     }
  720.  
  721.     This->rendering_done = TRUE;
  722. bypass_rendering:
  723.  
  724.     if (dwFlags & D3DPRESENT_DONOTWAIT) {
  725.         UNTESTED(2);
  726.         BOOL still_draw = FALSE;
  727.         fence = swap_fences_see_front(This);
  728.         if (fence) {
  729.             still_draw = !This->screen->fence_signalled(This->screen, fence);
  730.             This->screen->fence_reference(This->screen, &fence, NULL);
  731.         }
  732.         if (still_draw)
  733.             return D3DERR_WASSTILLDRAWING;
  734.     }
  735.  
  736.     if (This->present_buffers)
  737.         resource = This->present_buffers[0];
  738.     else
  739.         resource = This->buffers[0]->base.resource;
  740.     This->pipe->flush_resource(This->pipe, resource);
  741.  
  742.     if (!This->enable_threadpool) {
  743.         This->tasks[0]=NULL;
  744.         fence = swap_fences_pop_front(This);
  745.         if (fence) {
  746.             (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE);
  747.             This->screen->fence_reference(This->screen, &fence, NULL);
  748.         }
  749.  
  750.         hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags);
  751.  
  752.         if (FAILED(hr)) { UNTESTED(3);return hr; }
  753.     } else {
  754.         pend_present(This, hDestWindowOverride);
  755.     }
  756.     This->rendering_done = FALSE;
  757.  
  758.     return D3D_OK;
  759. }
  760.  
  761. HRESULT WINAPI
  762. NineSwapChain9_Present( struct NineSwapChain9 *This,
  763.                         const RECT *pSourceRect,
  764.                         const RECT *pDestRect,
  765.                         HWND hDestWindowOverride,
  766.                         const RGNDATA *pDirtyRegion,
  767.                         DWORD dwFlags )
  768. {
  769.     struct pipe_resource *res = NULL;
  770.     D3DWindowBuffer *handle_temp;
  771.     struct threadpool_task *task_temp;
  772.     int i;
  773.     HRESULT hr = present(This, pSourceRect, pDestRect,
  774.                          hDestWindowOverride, pDirtyRegion, dwFlags);
  775.  
  776.     DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p "
  777.         "pDirtyRegion=%p dwFlags=%d\n",
  778.         This, pSourceRect, pDestRect, hDestWindowOverride,
  779.         pDirtyRegion,dwFlags);
  780.  
  781.     if (hr == D3DERR_WASSTILLDRAWING)
  782.         return hr;
  783.  
  784.     switch (This->params.SwapEffect) {
  785.         case D3DSWAPEFFECT_FLIP:
  786.             UNTESTED(4);
  787.         case D3DSWAPEFFECT_DISCARD:
  788.             /* rotate the queue */;
  789.             pipe_resource_reference(&res, This->buffers[0]->base.resource);
  790.             for (i = 1; i <= This->params.BackBufferCount; i++) {
  791.                 NineSurface9_SetResourceResize(This->buffers[i - 1],
  792.                                                This->buffers[i]->base.resource);
  793.             }
  794.             NineSurface9_SetResourceResize(
  795.                 This->buffers[This->params.BackBufferCount], res);
  796.             pipe_resource_reference(&res, NULL);
  797.  
  798.             if (This->present_buffers) {
  799.                 pipe_resource_reference(&res, This->present_buffers[0]);
  800.                 for (i = 1; i <= This->params.BackBufferCount; i++)
  801.                     pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
  802.                 pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res);
  803.                 pipe_resource_reference(&res, NULL);
  804.             }
  805.  
  806.             handle_temp = This->present_handles[0];
  807.             for (i = 1; i <= This->params.BackBufferCount; i++) {
  808.                 This->present_handles[i-1] = This->present_handles[i];
  809.             }
  810.             This->present_handles[This->params.BackBufferCount] = handle_temp;
  811.             task_temp = This->tasks[0];
  812.             for (i = 1; i <= This->params.BackBufferCount; i++) {
  813.                 This->tasks[i-1] = This->tasks[i];
  814.             }
  815.             This->tasks[This->params.BackBufferCount] = task_temp;
  816.             break;
  817.  
  818.         case D3DSWAPEFFECT_COPY:
  819.             UNTESTED(5);
  820.             /* do nothing */
  821.             break;
  822.  
  823.         case D3DSWAPEFFECT_OVERLAY:
  824.             /* XXX not implemented */
  825.             break;
  826.  
  827.         case D3DSWAPEFFECT_FLIPEX:
  828.             /* XXX not implemented */
  829.             break;
  830.     }
  831.  
  832.     if (This->tasks[0])
  833.         _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
  834.  
  835.     ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
  836.  
  837.     This->base.device->state.changed.group |= NINE_STATE_FB;
  838.     nine_update_state(This->base.device, NINE_STATE_FB);
  839.  
  840.     return hr;
  841. }
  842.  
  843. HRESULT WINAPI
  844. NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
  845.                                    IDirect3DSurface9 *pDestSurface )
  846. {
  847.     struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
  848.     struct NineDevice9 *pDevice = This->base.device;
  849.     unsigned int width, height;
  850.     struct pipe_resource *temp_resource;
  851.     struct NineSurface9 *temp_surface;
  852.     D3DWindowBuffer *temp_handle;
  853.     D3DSURFACE_DESC desc;
  854.     HRESULT hr;
  855.  
  856.     DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
  857.         This, pDestSurface);
  858.  
  859.     width = dest_surface->desc.Width;
  860.     height = dest_surface->desc.Height;
  861.  
  862.     /* Note: front window size and destination size are supposed
  863.      * to match. However it's not very clear what should get taken in Windowed
  864.      * mode. It may need a fix */
  865.     create_present_buffer(This, width, height, &temp_resource, &temp_handle);
  866.  
  867.     desc.Type = D3DRTYPE_SURFACE;
  868.     desc.Pool = D3DPOOL_DEFAULT;
  869.     desc.MultiSampleType = D3DMULTISAMPLE_NONE;
  870.     desc.MultiSampleQuality = 0;
  871.     desc.Width = width;
  872.     desc.Height = height;
  873.     /* NineSurface9_CopySurface needs same format. */
  874.     desc.Format = dest_surface->desc.Format;
  875.     desc.Usage = D3DUSAGE_RENDERTARGET;
  876.     hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0,
  877.                           0, 0, &desc, &temp_surface);
  878.     pipe_resource_reference(&temp_resource, NULL);
  879.     if (FAILED(hr)) {
  880.         DBG("Failed to create temp FrontBuffer surface.\n");
  881.         return hr;
  882.     }
  883.  
  884.     ID3DPresent_FrontBufferCopy(This->present, temp_handle);
  885.  
  886.     NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL);
  887.  
  888.     ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
  889.     NineUnknown_Destroy(NineUnknown(temp_surface));
  890.  
  891.     return D3D_OK;
  892. }
  893.  
  894. HRESULT WINAPI
  895. NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
  896.                               UINT iBackBuffer,
  897.                               D3DBACKBUFFER_TYPE Type,
  898.                               IDirect3DSurface9 **ppBackBuffer )
  899. {
  900.     DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
  901.         This, iBackBuffer, Type, ppBackBuffer);
  902.     (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
  903.     user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
  904.     user_assert(ppBackBuffer != NULL, E_POINTER);
  905.  
  906.     NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
  907.     *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
  908.     return D3D_OK;
  909. }
  910.  
  911. HRESULT WINAPI
  912. NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
  913.                                 D3DRASTER_STATUS *pRasterStatus )
  914. {
  915.     DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
  916.         This, pRasterStatus);
  917.     user_assert(pRasterStatus != NULL, E_POINTER);
  918.     return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
  919. }
  920.  
  921. HRESULT WINAPI
  922. NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
  923.                                D3DDISPLAYMODE *pMode )
  924. {
  925.     D3DDISPLAYMODEEX mode;
  926.     D3DDISPLAYROTATION rot;
  927.     HRESULT hr;
  928.  
  929.     DBG("GetDisplayMode: This=%p pMode=%p\n",
  930.         This, pMode);
  931.     user_assert(pMode != NULL, E_POINTER);
  932.  
  933.     hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
  934.     if (SUCCEEDED(hr)) {
  935.         pMode->Width = mode.Width;
  936.         pMode->Height = mode.Height;
  937.         pMode->RefreshRate = mode.RefreshRate;
  938.         pMode->Format = mode.Format;
  939.     }
  940.     return hr;
  941. }
  942.  
  943. HRESULT WINAPI
  944. NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
  945.                                      D3DPRESENT_PARAMETERS *pPresentationParameters )
  946. {
  947.     DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
  948.         This, pPresentationParameters);
  949.     user_assert(pPresentationParameters != NULL, E_POINTER);
  950.     *pPresentationParameters = This->params;
  951.     return D3D_OK;
  952. }
  953.  
  954. IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
  955.     (void *)NineUnknown_QueryInterface,
  956.     (void *)NineUnknown_AddRef,
  957.     (void *)NineUnknown_Release,
  958.     (void *)NineSwapChain9_Present,
  959.     (void *)NineSwapChain9_GetFrontBufferData,
  960.     (void *)NineSwapChain9_GetBackBuffer,
  961.     (void *)NineSwapChain9_GetRasterStatus,
  962.     (void *)NineSwapChain9_GetDisplayMode,
  963.     (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
  964.     (void *)NineSwapChain9_GetPresentParameters
  965. };
  966.  
  967. static const GUID *NineSwapChain9_IIDs[] = {
  968.     &IID_IDirect3DSwapChain9,
  969.     &IID_IUnknown,
  970.     NULL
  971. };
  972.  
  973. HRESULT
  974. NineSwapChain9_new( struct NineDevice9 *pDevice,
  975.                     BOOL implicit,
  976.                     ID3DPresent *pPresent,
  977.                     D3DPRESENT_PARAMETERS *pPresentationParameters,
  978.                     struct d3dadapter9_context *pCTX,
  979.                     HWND hFocusWindow,
  980.                     struct NineSwapChain9 **ppOut )
  981. {
  982.     NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
  983.                           implicit, pPresent, pPresentationParameters,
  984.                           pCTX, hFocusWindow, NULL);
  985. }
  986.