st/nine: Implement Fast path for dynamic buffers and csmt
authorAxel Davy <axel.davy@ens.fr>
Thu, 3 Nov 2016 22:37:46 +0000 (23:37 +0100)
committerAxel Davy <axel.davy@ens.fr>
Tue, 20 Dec 2016 22:44:23 +0000 (23:44 +0100)
Use the secondary pipe for DISCARD/NOOVERWRITE, which
avoids stalling to get the pipe from the worker thread.

v2: flush at unmap. This is required for example if
the driver does hidden draw calls or copies. In the case
of unsynchronized it is probably not required, but
it is more safe.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/buffer9.c
src/gallium/state_trackers/nine/buffer9.h
src/gallium/state_trackers/nine/indexbuffer9.c

index e497222434b2fac1cebbe253730f40d34a960e3a..bd115ff70b1ad8887c3e5564d85e88b4e929158b 100644 (file)
@@ -32,6 +32,7 @@
 #include "pipe/p_defines.h"
 #include "pipe/p_format.h"
 #include "util/u_box.h"
+#include "util/u_inlines.h"
 
 #define DBG_CHANNEL (DBG_INDEXBUFFER|DBG_VERTEXBUFFER)
 
@@ -50,7 +51,7 @@ NineBuffer9_ctor( struct NineBuffer9 *This,
 
     user_assert(Pool != D3DPOOL_SCRATCH, D3DERR_INVALIDCALL);
 
-    This->maps = MALLOC(sizeof(struct pipe_transfer *));
+    This->maps = MALLOC(sizeof(struct NineTransfer));
     if (!This->maps)
         return E_OUTOFMEMORY;
     This->nmaps = 0;
@@ -169,6 +170,25 @@ NineBuffer9_GetResource( struct NineBuffer9 *This )
     return NineResource9_GetResource(&This->base);
 }
 
+static void
+NineBuffer9_RebindIfRequired( struct NineBuffer9 *This,
+                              struct NineDevice9 *device )
+{
+    int i;
+
+    if (!This->bind_count)
+        return;
+    for (i = 0; i < device->caps.MaxStreams; i++) {
+        if (device->state.stream[i] == (struct NineVertexBuffer9 *)This)
+            nine_context_set_stream_source(device, i,
+                                           (struct NineVertexBuffer9 *)This,
+                                           device->state.vtxbuf[i].buffer_offset,
+                                           device->state.vtxbuf[i].stride);
+    }
+    if (device->state.idxbuf == (struct NineIndexBuffer9 *)This)
+        nine_context_set_indices(device, (struct NineIndexBuffer9 *)This);
+}
+
 HRESULT NINE_WINAPI
 NineBuffer9_Lock( struct NineBuffer9 *This,
                         UINT OffsetToLock,
@@ -176,6 +196,7 @@ NineBuffer9_Lock( struct NineBuffer9 *This,
                         void **ppbData,
                         DWORD Flags )
 {
+    struct NineDevice9 *device = This->base.base.device;
     struct pipe_box box;
     struct pipe_context *pipe;
     void *data;
@@ -241,9 +262,9 @@ NineBuffer9_Lock( struct NineBuffer9 *This,
         usage |= PIPE_TRANSFER_DONTBLOCK;
 
     if (This->nmaps == This->maxmaps) {
-        struct pipe_transfer **newmaps =
-            REALLOC(This->maps, sizeof(struct pipe_transfer *)*This->maxmaps,
-                    sizeof(struct pipe_transfer *)*(This->maxmaps << 1));
+        struct NineTransfer *newmaps =
+            REALLOC(This->maps, sizeof(struct NineTransfer)*This->maxmaps,
+                    sizeof(struct NineTransfer)*(This->maxmaps << 1));
         if (newmaps == NULL)
             return E_OUTOFMEMORY;
 
@@ -251,9 +272,29 @@ NineBuffer9_Lock( struct NineBuffer9 *This,
         This->maps = newmaps;
     }
 
-    pipe = NineDevice9_GetPipe(This->base.base.device);
+    This->maps[This->nmaps].is_pipe_secondary = FALSE;
+
+    if (Flags & D3DLOCK_DISCARD && device->csmt_active) {
+        struct pipe_screen *screen = NineDevice9_GetScreen(device);
+        struct pipe_resource *new_res = screen->resource_create(screen, &This->base.info);
+        if (new_res) {
+            /* Use the new resource */
+            pipe_resource_reference(&This->base.resource, new_res);
+            pipe_resource_reference(&new_res, NULL);
+            usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_UNSYNCHRONIZED;
+            NineBuffer9_RebindIfRequired(This, device);
+            This->maps[This->nmaps].is_pipe_secondary = TRUE;
+        }
+    } else if (Flags & D3DLOCK_NOOVERWRITE && device->csmt_active)
+        This->maps[This->nmaps].is_pipe_secondary = TRUE;
+
+    if (This->maps[This->nmaps].is_pipe_secondary)
+        pipe = device->pipe_secondary;
+    else
+        pipe = NineDevice9_GetPipe(device);
+
     data = pipe->transfer_map(pipe, This->base.resource, 0,
-                              usage, &box, &This->maps[This->nmaps]);
+                              usage, &box, &This->maps[This->nmaps].transfer);
 
     if (!data) {
         DBG("pipe::transfer_map failed\n"
@@ -277,15 +318,21 @@ NineBuffer9_Lock( struct NineBuffer9 *This,
 HRESULT NINE_WINAPI
 NineBuffer9_Unlock( struct NineBuffer9 *This )
 {
+    struct NineDevice9 *device = This->base.base.device;
     struct pipe_context *pipe;
     DBG("This=%p\n", This);
 
     user_assert(This->nmaps > 0, D3DERR_INVALIDCALL);
+    This->nmaps--;
     if (This->base.pool != D3DPOOL_MANAGED) {
-        pipe = NineDevice9_GetPipe(This->base.base.device);
-        pipe->transfer_unmap(pipe, This->maps[--(This->nmaps)]);
+        pipe = This->maps[This->nmaps].is_pipe_secondary ?
+            device->pipe_secondary :
+            NineDevice9_GetPipe(device);
+        pipe->transfer_unmap(pipe, This->maps[This->nmaps].transfer);
+        /* We need to flush in case the driver does implicit copies */
+        if (This->maps[This->nmaps].is_pipe_secondary)
+            pipe->flush(pipe, NULL, 0);
     } else {
-        This->nmaps--;
         BASEBUF_REGISTER_UPDATE(This);
     }
     return D3D_OK;
index 49b67a9eaf9471767a998c0786b693fb83662bee..d8024e4aac2facd9db5a0e5e01e54d39ffffaa21 100644 (file)
@@ -34,12 +34,17 @@ struct pipe_screen;
 struct pipe_context;
 struct pipe_transfer;
 
+struct NineTransfer {
+    struct pipe_transfer *transfer;
+    bool is_pipe_secondary;
+};
+
 struct NineBuffer9
 {
     struct NineResource9 base;
 
     /* G3D */
-    struct pipe_transfer **maps;
+    struct NineTransfer *maps;
     int nmaps, maxmaps;
     UINT size;
 
index 4e65ed7bc085201c794dd9e31a0a6f2708210877..4029a8d6a3a82374b03bb4b0ba4369ad66105690 100644 (file)
@@ -76,6 +76,8 @@ NineIndexBuffer9_dtor( struct NineIndexBuffer9 *This )
 const struct pipe_index_buffer *
 NineIndexBuffer9_GetBuffer( struct NineIndexBuffer9 *This )
 {
+    /* The resource may change */
+    This->buffer.buffer = NineIndexBuffer9_GetResource(This);
     return &This->buffer;
 }