ac: initial Wave32 support in LLVM build helpers
[mesa.git] / src / gallium / state_trackers / nine / surface9.c
index 26c2d69d276ab0725a99db2440247cf0e397d385..db74de2823acd0fe640b70a9903b849b2a9e0128 100644 (file)
@@ -20,6 +20,7 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
 
+#include "iunknown.h"
 #include "surface9.h"
 #include "device9.h"
 
@@ -43,6 +44,9 @@
 
 #define DBG_CHANNEL DBG_SURFACE
 
+static void
+NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This );
+
 HRESULT
 NineSurface9_ctor( struct NineSurface9 *This,
                    struct NineUnknownParams *pParams,
@@ -100,12 +104,15 @@ NineSurface9_ctor( struct NineSurface9 *This,
     This->base.info.last_level = 0;
     This->base.info.array_size = 1;
     This->base.info.nr_samples = multisample_type;
+    This->base.info.nr_storage_samples = multisample_type;
     This->base.info.usage = PIPE_USAGE_DEFAULT;
     This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */
 
     if (pDesc->Usage & D3DUSAGE_RENDERTARGET) {
         This->base.info.bind |= PIPE_BIND_RENDER_TARGET;
     } else if (pDesc->Usage & D3DUSAGE_DEPTHSTENCIL) {
+        if (!depth_stencil_format(pDesc->Format))
+            return D3DERR_INVALIDCALL;
         This->base.info.bind = d3d9_get_pipe_depth_format_bindings(pDesc->Format);
         if (TextureType)
             This->base.info.bind |= PIPE_BIND_SAMPLER_VIEW;
@@ -132,22 +139,26 @@ NineSurface9_ctor( struct NineSurface9 *This,
     }
 
     /* Get true format */
-    This->format_conversion = d3d9_to_pipe_format_checked(This->base.info.screen,
+    This->format_internal = d3d9_to_pipe_format_checked(This->base.info.screen,
                                                          pDesc->Format,
                                                          This->base.info.target,
                                                          This->base.info.nr_samples,
                                                          This->base.info.bind,
                                                          FALSE,
                                                          TRUE);
-    if (This->base.info.format != This->format_conversion) {
-        This->data_conversion = align_calloc(
-            nine_format_get_level_alloc_size(This->format_conversion,
+    if (This->base.info.format != This->format_internal ||
+        /* DYNAMIC Textures requires same stride as ram buffers.
+         * Do not use workaround by default as it eats more virtual space */
+        (pParams->device->workarounds.dynamic_texture_workaround &&
+         pDesc->Pool == D3DPOOL_DEFAULT && pDesc->Usage & D3DUSAGE_DYNAMIC)) {
+        This->data_internal = align_calloc(
+            nine_format_get_level_alloc_size(This->format_internal,
                                              pDesc->Width,
                                              pDesc->Height,
                                              0), 32);
-        if (!This->data_conversion)
+        if (!This->data_internal)
             return E_OUTOFMEMORY;
-        This->stride_conversion = nine_format_get_stride(This->format_conversion,
+        This->stride_internal = nine_format_get_stride(This->format_internal,
                                                          pDesc->Width);
     }
 
@@ -183,10 +194,8 @@ NineSurface9_ctor( struct NineSurface9 *This,
     if (This->base.resource && (pDesc->Usage & D3DUSAGE_DYNAMIC))
         This->base.resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
 
-    if (This->base.resource && (pDesc->Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))) {
-        (void) NineSurface9_CreatePipeSurface(This, 0);
-        (void) NineSurface9_CreatePipeSurface(This, 1);
-    }
+    if (This->base.resource && (pDesc->Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL)))
+        NineSurface9_CreatePipeSurfaces(This);
 
     /* TODO: investigate what else exactly needs to be cleared */
     if (This->base.resource && (pDesc->Usage & D3DUSAGE_RENDERTARGET))
@@ -202,9 +211,15 @@ NineSurface9_dtor( struct NineSurface9 *This )
 {
     DBG("This=%p\n", This);
 
-    if (This->transfer)
-        NineSurface9_UnlockRect(This);
+    if (This->transfer) {
+        struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.base.device);
+        pipe->transfer_unmap(pipe, This->transfer);
+        This->transfer = NULL;
+    }
 
+    /* Note: Following condition cannot happen currently, since we
+     * refcount the surface in the functions increasing
+     * pending_uploads_counter. */
     if (p_atomic_read(&This->pending_uploads_counter))
         nine_csmt_process(This->base.base.device);
 
@@ -214,13 +229,13 @@ NineSurface9_dtor( struct NineSurface9 *This )
     /* Release system memory when we have to manage it (no parent) */
     if (!This->base.base.container && This->data)
         align_free(This->data);
-    if (This->data_conversion)
-        align_free(This->data_conversion);
+    if (This->data_internal)
+        align_free(This->data_internal);
     NineResource9_dtor(&This->base);
 }
 
-struct pipe_surface *
-NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
+static void
+NineSurface9_CreatePipeSurfaces( struct NineSurface9 *This )
 {
     struct pipe_context *pipe;
     struct pipe_screen *screen = NineDevice9_GetScreen(This->base.base.device);
@@ -232,24 +247,36 @@ NineSurface9_CreatePipeSurface( struct NineSurface9 *This, const int sRGB )
     assert(resource);
 
     srgb_format = util_format_srgb(resource->format);
-    if (sRGB && srgb_format != PIPE_FORMAT_NONE &&
-        screen->is_format_supported(screen, srgb_format,
-                                    resource->target, 0, resource->bind))
-        templ.format = srgb_format;
-    else
-        templ.format = resource->format;
+    if (srgb_format == PIPE_FORMAT_NONE ||
+        !screen->is_format_supported(screen, srgb_format,
+                                     resource->target, 0, 0, resource->bind))
+        srgb_format = resource->format;
+
+    memset(&templ, 0, sizeof(templ));
+    templ.format = resource->format;
     templ.u.tex.level = This->level;
     templ.u.tex.first_layer = This->layer;
     templ.u.tex.last_layer = This->layer;
 
     pipe = nine_context_get_pipe_acquire(This->base.base.device);
-    This->surface[sRGB] = pipe->create_surface(pipe, resource, &templ);
+
+    This->surface[0] = pipe->create_surface(pipe, resource, &templ);
+
+    memset(&templ, 0, sizeof(templ));
+    templ.format = srgb_format;
+    templ.u.tex.level = This->level;
+    templ.u.tex.first_layer = This->layer;
+    templ.u.tex.last_layer = This->layer;
+
+    This->surface[1] = pipe->create_surface(pipe, resource, &templ);
+
     nine_context_get_pipe_release(This->base.base.device);
-    assert(This->surface[sRGB]);
-    return This->surface[sRGB];
+
+    assert(This->surface[0]); /* TODO: Handle failure */
+    assert(This->surface[1]);
 }
 
-#ifdef DEBUG
+#if defined(DEBUG) || !defined(NDEBUG)
 void
 NineSurface9_Dump( struct NineSurface9 *This )
 {
@@ -277,7 +304,7 @@ NineSurface9_Dump( struct NineSurface9 *This )
         NineUnknown_Release(NineUnknown(tex));
     }
 }
-#endif /* DEBUG */
+#endif /* DEBUG || !NDEBUG */
 
 HRESULT NINE_WINAPI
 NineSurface9_GetContainer( struct NineSurface9 *This,
@@ -371,15 +398,15 @@ NineSurface9_AddDirtyRect( struct NineSurface9 *This,
     }
 }
 
-static inline uint8_t *
-NineSurface9_GetSystemMemPointer(struct NineSurface9 *This, int x, int y)
+static inline unsigned
+NineSurface9_GetSystemMemOffset(enum pipe_format format, unsigned stride,
+                                int x, int y)
 {
-    unsigned x_offset = util_format_get_stride(This->base.info.format, x);
+    unsigned x_offset = util_format_get_stride(format, x);
 
-    y = util_format_get_nblocksy(This->base.info.format, y);
+    y = util_format_get_nblocksy(format, y);
 
-    assert(This->data);
-    return This->data + (y * This->stride + x_offset);
+    return y * stride + x_offset;
 }
 
 HRESULT NINE_WINAPI
@@ -458,34 +485,48 @@ NineSurface9_LockRect( struct NineSurface9 *This,
     if (p_atomic_read(&This->pending_uploads_counter))
         nine_csmt_process(This->base.base.device);
 
-    if (This->data_conversion) {
-        /* For now we only have uncompressed formats here */
-        pLockedRect->Pitch = This->stride_conversion;
-        pLockedRect->pBits = This->data_conversion + box.y * This->stride_conversion +
-            util_format_get_stride(This->format_conversion, box.x);
-    } else if (This->data) {
+    if (This->data_internal || This->data) {
+        enum pipe_format format = This->base.info.format;
+        unsigned stride = This->stride;
+        uint8_t *data = This->data;
+        if (This->data_internal) {
+            format = This->format_internal;
+            stride = This->stride_internal;
+            data = This->data_internal;
+        }
         DBG("returning system memory\n");
         /* ATI1 and ATI2 need special handling, because of d3d9 bug.
          * We must advertise to the application as if it is uncompressed
          * and bpp 8, and the app has a workaround to work with the fact
          * that it is actually compressed. */
-        if (is_ATI1_ATI2(This->base.info.format)) {
+        if (is_ATI1_ATI2(format)) {
             pLockedRect->Pitch = This->desc.Width;
-            pLockedRect->pBits = This->data + box.y * This->desc.Width + box.x;
+            pLockedRect->pBits = data + box.y * This->desc.Width + box.x;
         } else {
-            pLockedRect->Pitch = This->stride;
-            pLockedRect->pBits = NineSurface9_GetSystemMemPointer(This,
-                                                                  box.x,
-                                                                  box.y);
+            pLockedRect->Pitch = stride;
+            pLockedRect->pBits = data +
+                NineSurface9_GetSystemMemOffset(format,
+                                                stride,
+                                                box.x,
+                                                box.y);
         }
     } else {
+        bool no_refs = !p_atomic_read(&This->base.base.bind) &&
+            !(This->base.base.container && p_atomic_read(&This->base.base.container->bind));
         DBG("mapping pipe_resource %p (level=%u usage=%x)\n",
             resource, This->level, usage);
 
-        pipe = NineDevice9_GetPipe(This->base.base.device);
+        /* if the object is not bound internally, there can't be any pending
+         * operation with the surface in the queue */
+        if (no_refs)
+            pipe = nine_context_get_pipe_acquire(This->base.base.device);
+        else
+            pipe = NineDevice9_GetPipe(This->base.base.device);
         pLockedRect->pBits = pipe->transfer_map(pipe, resource,
                                                 This->level, usage, &box,
                                                 &This->transfer);
+        if (no_refs)
+            nine_context_get_pipe_release(This->base.base.device);
         if (!This->transfer) {
             DBG("transfer_map failed\n");
             if (Flags & D3DLOCK_DONOTWAIT)
@@ -507,6 +548,7 @@ NineSurface9_LockRect( struct NineSurface9 *This,
 HRESULT NINE_WINAPI
 NineSurface9_UnlockRect( struct NineSurface9 *This )
 {
+    struct pipe_box dst_box, src_box;
     struct pipe_context *pipe;
     DBG("This=%p lock_count=%u\n", This, This->lock_count);
     user_assert(This->lock_count, D3DERR_INVALIDCALL);
@@ -518,36 +560,34 @@ NineSurface9_UnlockRect( struct NineSurface9 *This )
     }
     --This->lock_count;
 
-    if (This->data_conversion) {
-        struct pipe_transfer *transfer;
-        uint8_t *dst = This->data;
-        struct pipe_box box;
-
-        u_box_origin_2d(This->desc.Width, This->desc.Height, &box);
-
-        pipe = NineDevice9_GetPipe(This->base.base.device);
-        if (!dst) {
-            dst = pipe->transfer_map(pipe,
-                                     This->base.resource,
-                                     This->level,
-                                     PIPE_TRANSFER_WRITE |
-                                     PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE,
-                                     &box, &transfer);
-            if (!dst)
-                return D3D_OK;
+    if (This->data_internal) {
+        if (This->data) {
+            (void) util_format_translate(This->base.info.format,
+                                         This->data, This->stride,
+                                         0, 0,
+                                         This->format_internal,
+                                         This->data_internal,
+                                         This->stride_internal,
+                                         0, 0,
+                                         This->desc.Width, This->desc.Height);
+        } else {
+            u_box_2d_zslice(0, 0, This->layer,
+                            This->desc.Width, This->desc.Height, &dst_box);
+            u_box_2d_zslice(0, 0, 0,
+                            This->desc.Width, This->desc.Height, &src_box);
+
+            nine_context_box_upload(This->base.base.device,
+                                    &This->pending_uploads_counter,
+                                    (struct NineUnknown *)This,
+                                    This->base.resource,
+                                    This->level,
+                                    &dst_box,
+                                    This->format_internal,
+                                    This->data_internal,
+                                    This->stride_internal,
+                                    0, /* depth = 1 */
+                                    &src_box);
         }
-
-        (void) util_format_translate(This->base.info.format,
-                                     dst, This->data ? This->stride : transfer->stride,
-                                     0, 0,
-                                     This->format_conversion,
-                                     This->data_conversion,
-                                     This->stride_conversion,
-                                     0, 0,
-                                     This->desc.Width, This->desc.Height);
-
-        if (!This->data)
-            pipe_transfer_unmap(pipe, transfer);
     }
     return D3D_OK;
 }
@@ -628,7 +668,7 @@ NineSurface9_CopyMemToDefault( struct NineSurface9 *This,
 
     nine_context_box_upload(This->base.base.device,
                             &From->pending_uploads_counter,
-                            (struct NineUnknown *)This,
+                            (struct NineUnknown *)From,
                             r_dst,
                             This->level,
                             &dst_box,
@@ -636,11 +676,24 @@ NineSurface9_CopyMemToDefault( struct NineSurface9 *This,
                             From->data, From->stride,
                             0, /* depth = 1 */
                             &src_box);
+    if (From->texture == D3DRTYPE_TEXTURE) {
+        struct NineTexture9 *tex =
+            NineTexture9(From->base.base.container);
+        /* D3DPOOL_SYSTEMMEM with buffer content passed
+         * from the user: execute the upload right now.
+         * It is possible it is enough to delay upload
+         * until the surface refcount is 0, but the
+         * bind refcount may not be 0, and thus the dtor
+         * is not executed (and doesn't trigger the
+         * pending_uploads_counter check). */
+        if (!tex->managed_buffer)
+            nine_csmt_process(This->base.base.device);
+    }
 
-    if (This->data_conversion)
-        (void) util_format_translate(This->format_conversion,
-                                     This->data_conversion,
-                                     This->stride_conversion,
+    if (This->data_internal)
+        (void) util_format_translate(This->format_internal,
+                                     This->data_internal,
+                                     This->stride_internal,
                                      dst_x, dst_y,
                                      From->base.info.format,
                                      From->data, From->stride,
@@ -677,7 +730,7 @@ NineSurface9_CopyDefaultToMem( struct NineSurface9 *This,
     p_src = pipe->transfer_map(pipe, r_src, From->level,
                                PIPE_TRANSFER_READ,
                                &src_box, &transfer);
-    p_dst = NineSurface9_GetSystemMemPointer(This, 0, 0);
+    p_dst = This->data;
 
     assert (p_src && p_dst);
 
@@ -732,6 +785,33 @@ NineSurface9_UploadSelf( struct NineSurface9 *This,
     return D3D_OK;
 }
 
+/* Currently nine_context uses the NineSurface9
+ * fields when it is render target. Any modification requires
+ * pending commands with the surface to be executed. If the bind
+ * count is 0, there is no pending commands. */
+#define PROCESS_IF_BOUND(surf) \
+    if (surf->base.base.bind) \
+        nine_csmt_process(surf->base.base.device);
+
+void
+NineSurface9_SetResource( struct NineSurface9 *This,
+                          struct pipe_resource *resource, unsigned level )
+{
+    /* No need to call PROCESS_IF_BOUND, because SetResource is used only
+     * for MANAGED textures, and they are not render targets. */
+    assert(This->base.pool == D3DPOOL_MANAGED);
+    This->level = level;
+    pipe_resource_reference(&This->base.resource, resource);
+}
+
+void
+NineSurface9_SetMultiSampleType( struct NineSurface9 *This,
+                                 D3DMULTISAMPLE_TYPE mst )
+{
+    PROCESS_IF_BOUND(This);
+    This->desc.MultiSampleType = mst;
+}
+
 void
 NineSurface9_SetResourceResize( struct NineSurface9 *This,
                                 struct pipe_resource *resource )
@@ -741,21 +821,21 @@ NineSurface9_SetResourceResize( struct NineSurface9 *This,
     assert(This->desc.Pool == D3DPOOL_DEFAULT);
     assert(!This->texture);
 
+    PROCESS_IF_BOUND(This);
     pipe_resource_reference(&This->base.resource, resource);
 
     This->desc.Width = This->base.info.width0 = resource->width0;
     This->desc.Height = This->base.info.height0 = resource->height0;
     This->base.info.nr_samples = resource->nr_samples;
+    This->base.info.nr_storage_samples = resource->nr_storage_samples;
 
     This->stride = nine_format_get_stride(This->base.info.format,
                                           This->desc.Width);
 
     pipe_surface_reference(&This->surface[0], NULL);
     pipe_surface_reference(&This->surface[1], NULL);
-    if (resource) {
-        (void) NineSurface9_CreatePipeSurface(This, 0);
-        (void) NineSurface9_CreatePipeSurface(This, 1);
-    }
+    if (resource)
+        NineSurface9_CreatePipeSurfaces(This);
 }