llvmpipe: add LP_NEW_GS flag for updating vertex info
[mesa.git] / src / gallium / state_trackers / nine / swapchain9.c
index 03bdcd33efe4baab00d981cc65ef1adfc58eb2a0..9815acf7a4a7007497c1b2fad063e45ad1607855 100644 (file)
@@ -59,14 +59,21 @@ NineSwapChain9_ctor( struct NineSwapChain9 *This,
         return hr;
 
     This->screen = NineDevice9_GetScreen(This->base.device);
-    This->pipe = NineDevice9_GetPipe(This->base.device);
-    This->cso = NineDevice9_GetCSO(This->base.device);
     This->implicit = implicit;
     This->actx = pCTX;
     This->present = pPresent;
     This->mode = NULL;
 
     ID3DPresent_AddRef(pPresent);
+    if (!This->actx->thread_submit &&
+        This->base.device->minor_version_num > 2) {
+        D3DPRESENT_PARAMETERS2 params2;
+
+        memset(&params2, 0, sizeof(D3DPRESENT_PARAMETERS2));
+        params2.AllowDISCARDDelayedRelease = This->actx->discard_delayed_release;
+        params2.TearFreeDISCARD = This->actx->tearfree_discard;
+        ID3DPresent_SetPresentParameters2(pPresent, &params2);
+    }
 
     if (!pPresentationParameters->hDeviceWindow)
         pPresentationParameters->hDeviceWindow = hFocusWindow;
@@ -83,18 +90,20 @@ D3DWindowBuffer_create(struct NineSwapChain9 *This,
                        int for_frontbuffer_reading)
 {
     D3DWindowBuffer *ret;
+    struct pipe_context *pipe = nine_context_get_pipe_acquire(This->base.device);
     struct winsys_handle whandle;
     int stride, dmaBufFd;
     HRESULT hr;
 
     memset(&whandle, 0, sizeof(whandle));
     whandle.type = DRM_API_HANDLE_TYPE_FD;
-    This->screen->resource_get_handle(This->screen, This->pipe, resource,
+    This->screen->resource_get_handle(This->screen, pipe, resource,
                                       &whandle,
                                       for_frontbuffer_reading ?
                                           PIPE_HANDLE_USAGE_WRITE :
                                           PIPE_HANDLE_USAGE_EXPLICIT_FLUSH |
                                           PIPE_HANDLE_USAGE_READ);
+    nine_context_get_pipe_release(This->base.device);
     stride = whandle.stride;
     dmaBufFd = whandle.handle;
     hr = ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
@@ -114,6 +123,10 @@ D3DWindowBuffer_create(struct NineSwapChain9 *This,
     return ret;
 }
 
+static int
+NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
+                                            D3DPRESENT_PARAMETERS *pParams );
+
 HRESULT
 NineSwapChain9_Resize( struct NineSwapChain9 *This,
                        D3DPRESENT_PARAMETERS *pParams,
@@ -203,14 +216,8 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
     if (hr != D3D_OK)
         return hr;
 
-    /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
-     * Here we don't get back the initial content of the screen. To emulate the behaviour
-     * we allocate an additional buffer */
-    oldBufferCount = This->params.BackBufferCount ?
-                     (This->params.BackBufferCount +
-                      (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0;
-    newBufferCount = pParams->BackBufferCount +
-                     (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
+    oldBufferCount = This->num_back_buffers;
+    newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams);
 
     multisample_type = pParams->MultiSampleType;
 
@@ -295,6 +302,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
             This->present_handles[i] = NULL;
         }
     }
+    This->num_back_buffers = newBufferCount;
 
     for (i = 0; i < newBufferCount; ++i) {
         tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
@@ -498,13 +506,13 @@ NineSwapChain9_dtor( struct NineSwapChain9 *This )
     if (This->pool)
         _mesa_threadpool_destroy(This, This->pool);
 
-    if (This->buffers[0]) {
-        for (i = 0; i < This->params.BackBufferCount; i++) {
-            NineUnknown_Release(NineUnknown(This->buffers[i]));
+    for (i = 0; i < This->num_back_buffers; i++) {
+        if (This->buffers[i])
+            NineUnknown_Detach(NineUnknown(This->buffers[i]));
+        if (This->present_handles[i])
             ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
-            if (This->present_buffers[i])
-                pipe_resource_reference(&(This->present_buffers[i]), NULL);
-        }
+        if (This->present_buffers[i])
+            pipe_resource_reference(&(This->present_buffers[i]), NULL);
     }
     if (This->zsbuf)
         NineUnknown_Unbind(NineUnknown(This->zsbuf));
@@ -553,6 +561,7 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r
 {
     struct NineDevice9 *device = This->base.device;
     struct pipe_blit_info blit;
+    struct pipe_context *pipe;
 
     if (device->cursor.software && device->cursor.visible && device->cursor.w) {
         memset(&blit, 0, sizeof(blit));
@@ -590,10 +599,13 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r
             blit.dst.box.x, blit.dst.box.y);
 
         blit.alpha_blend = TRUE;
-        This->pipe->blit(This->pipe, &blit);
+        pipe = NineDevice9_GetPipe(This->base.device);
+        pipe->blit(pipe, &blit);
     }
 
     if (device->hud && resource) {
+        /* Implicit use of context pipe */
+        (void)NineDevice9_GetPipe(This->base.device);
         hud_draw(device->hud, resource); /* XXX: no offset */
         /* HUD doesn't clobber stipple */
         nine_state_restore_non_cso(device);
@@ -642,6 +654,7 @@ present( struct NineSwapChain9 *This,
          const RGNDATA *pDirtyRegion,
          DWORD dwFlags )
 {
+    struct pipe_context *pipe;
     struct pipe_resource *resource;
     struct pipe_fence_handle *fence;
     HRESULT hr;
@@ -680,6 +693,8 @@ present( struct NineSwapChain9 *This,
     if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
         handle_draw_cursor_and_hud(This, resource);
 
+    pipe = NineDevice9_GetPipe(This->base.device);
+
     if (This->present_buffers[0]) {
         memset(&blit, 0, sizeof(blit));
         blit.src.resource = resource;
@@ -709,18 +724,18 @@ present( struct NineSwapChain9 *This,
         blit.scissor_enable = FALSE;
         blit.alpha_blend = FALSE;
 
-        This->pipe->blit(This->pipe, &blit);
+        pipe->blit(pipe, &blit);
     }
 
     /* The resource we present has to resolve fast clears
      * if needed (and other things) */
-    This->pipe->flush_resource(This->pipe, resource);
+    pipe->flush_resource(pipe, resource);
 
     if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
         handle_draw_cursor_and_hud(This, resource);
 
     fence = NULL;
-    This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
+    pipe->flush(pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
     if (fence) {
         swap_fences_push_back(This, fence);
         This->screen->fence_reference(This->screen, &fence, NULL);
@@ -781,6 +796,7 @@ NineSwapChain9_Present( struct NineSwapChain9 *This,
 
     if (This->base.device->ex) {
         if (NineSwapChain9_GetOccluded(This)) {
+            DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n");
             return S_PRESENT_OCCLUDED;
         }
     } else {
@@ -789,69 +805,107 @@ NineSwapChain9_Present( struct NineSwapChain9 *This,
             This->base.device->device_needs_reset = TRUE;
         }
         if (This->base.device->device_needs_reset) {
+            DBG("Device is lost. Returning D3DERR_DEVICELOST.\n");
             return D3DERR_DEVICELOST;
         }
     }
 
+    nine_csmt_process(This->base.device);
+
     hr = present(This, pSourceRect, pDestRect,
                  hDestWindowOverride, pDirtyRegion, dwFlags);
     if (hr == D3DERR_WASSTILLDRAWING)
         return hr;
 
-    switch (This->params.SwapEffect) {
-        case D3DSWAPEFFECT_FLIP:
-            UNTESTED(4);
-        case D3DSWAPEFFECT_DISCARD:
-            /* rotate the queue */
-            pipe_resource_reference(&res, This->buffers[0]->base.resource);
-            for (i = 1; i <= This->params.BackBufferCount; i++) {
-                NineSurface9_SetResourceResize(This->buffers[i - 1],
-                                               This->buffers[i]->base.resource);
+    if (This->base.device->minor_version_num > 2 &&
+        This->params.SwapEffect == D3DSWAPEFFECT_DISCARD &&
+        This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
+        !This->actx->thread_submit) {
+        int next_buffer = -1;
+
+        while (next_buffer == -1) {
+            /* Find a free backbuffer */
+            for (i = 1; i < This->num_back_buffers; i++) {
+                if (ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) {
+                    DBG("Found buffer released: %d\n", i);
+                    next_buffer = i;
+                    break;
+                }
+            }
+            if (next_buffer == -1) {
+                DBG("Found no buffer released. Waiting for event\n");
+                ID3DPresent_WaitBufferReleaseEvent(This->present);
             }
-            NineSurface9_SetResourceResize(
-                This->buffers[This->params.BackBufferCount], res);
+        }
+        /* Switch with the released buffer */
+        pipe_resource_reference(&res, This->buffers[0]->base.resource);
+        NineSurface9_SetResourceResize(
+            This->buffers[0], This->buffers[next_buffer]->base.resource);
+        NineSurface9_SetResourceResize(
+            This->buffers[next_buffer], res);
+        pipe_resource_reference(&res, NULL);
+
+        if (This->present_buffers[0]) {
+            pipe_resource_reference(&res, This->present_buffers[0]);
+            pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]);
+            pipe_resource_reference(&This->present_buffers[next_buffer], res);
             pipe_resource_reference(&res, NULL);
+        }
 
-            if (This->present_buffers[0]) {
-                pipe_resource_reference(&res, This->present_buffers[0]);
-                for (i = 1; i <= This->params.BackBufferCount; i++)
-                    pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
-                pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res);
-                pipe_resource_reference(&res, NULL);
-            }
+        handle_temp = This->present_handles[0];
+        This->present_handles[0] = This->present_handles[next_buffer];
+        This->present_handles[next_buffer] = handle_temp;
 
-            handle_temp = This->present_handles[0];
-            for (i = 1; i <= This->params.BackBufferCount; i++) {
-                This->present_handles[i-1] = This->present_handles[i];
-            }
-            This->present_handles[This->params.BackBufferCount] = handle_temp;
-            task_temp = This->tasks[0];
-            for (i = 1; i <= This->params.BackBufferCount; i++) {
-                This->tasks[i-1] = This->tasks[i];
-            }
-            This->tasks[This->params.BackBufferCount] = task_temp;
-            break;
+        /* Path not yet compatible with thread_submit */
+        assert(!This->tasks[0] && !This->tasks[next_buffer]);
+    } else {
+        switch (This->params.SwapEffect) {
+            case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */
+            case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */
+            case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */
+            case D3DSWAPEFFECT_FLIP:
+                /* rotate the queue */
+                pipe_resource_reference(&res, This->buffers[0]->base.resource);
+                for (i = 1; i < This->num_back_buffers; i++) {
+                    NineSurface9_SetResourceResize(This->buffers[i - 1],
+                                                   This->buffers[i]->base.resource);
+                }
+                NineSurface9_SetResourceResize(
+                    This->buffers[This->num_back_buffers - 1], res);
+                pipe_resource_reference(&res, NULL);
 
-        case D3DSWAPEFFECT_COPY:
-            UNTESTED(5);
-            /* do nothing */
-            break;
+                if (This->present_buffers[0]) {
+                    pipe_resource_reference(&res, This->present_buffers[0]);
+                    for (i = 1; i < This->num_back_buffers; i++)
+                        pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
+                    pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res);
+                    pipe_resource_reference(&res, NULL);
+                }
+
+                handle_temp = This->present_handles[0];
+                for (i = 1; i < This->num_back_buffers; i++) {
+                    This->present_handles[i-1] = This->present_handles[i];
+                }
+                This->present_handles[This->num_back_buffers - 1] = handle_temp;
+                task_temp = This->tasks[0];
+                for (i = 1; i < This->num_back_buffers; i++) {
+                    This->tasks[i-1] = This->tasks[i];
+                }
+                This->tasks[This->num_back_buffers - 1] = task_temp;
+                break;
+
+            case D3DSWAPEFFECT_COPY:
+                /* do nothing */
+                break;
+        }
 
-        case D3DSWAPEFFECT_OVERLAY:
-            /* XXX not implemented */
-            break;
+        if (This->tasks[0])
+            _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
 
-        case D3DSWAPEFFECT_FLIPEX:
-            /* XXX not implemented */
-            break;
+        ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
     }
 
-    if (This->tasks[0])
-        _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0]));
-
-    ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
-
-    This->base.device->state.changed.group |= NINE_STATE_FB;
+    This->base.device->context.changed.group |= NINE_STATE_FB;
 
     return hr;
 }
@@ -1047,3 +1101,43 @@ NineSwapChain9_WaitForThread( struct NineSwapChain9 *This,
         (void) ID3DPresent_WaitForThread(This->present, thread);
     }
 }
+
+static int
+NineSwapChain9_GetBackBufferCountForParams( struct NineSwapChain9 *This,
+                                            D3DPRESENT_PARAMETERS *pParams )
+{
+    int count = pParams->BackBufferCount;
+
+    /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
+     * Here we don't get back the initial content of the screen. To emulate the behaviour
+     * we allocate an additional buffer */
+    if (pParams->SwapEffect != D3DSWAPEFFECT_COPY)
+        count++;
+    /* With DISCARD, as there is no guarantee about the buffer contents, we can use
+     * an arbitrary number of buffers */
+    if (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD) {
+        /* thread_submit has a throttling equivalent to the throttling
+         * with throttling_value set to count-1. Most drivers use
+         * 2 for throttling_value. For performance use count of at least 3
+         * for thread_submit. */
+        if (This->actx->thread_submit && count < 3)
+            count = 3;
+        /* When we enable AllowDISCARDDelayedRelease, we must ensure
+         * to have at least 4 buffers to meet INTERVAL_IMMEDIATE,
+         * since the display server/compositor can hold 3 buffers
+         * without releasing them:
+         * . Buffer on screen.
+         * . Buffer scheduled kernel side to be next on screen.
+         * . Last buffer sent.
+         * For some reasons, 5 buffers are actually needed, because in
+         * case a pageflip is missed because rendering wasn't finished,
+         * the Xserver will hold 4 buffers. */
+        if (!This->actx->thread_submit &&
+            This->base.device->minor_version_num > 2 &&
+            pParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
+            count < 5)
+            count = 5;
+    }
+
+    return count;
+}