st/nine: Fix volumetexture dtor on ctor failure
[mesa.git] / src / gallium / state_trackers / nine / surface9.c
index 26c2d69d276ab0725a99db2440247cf0e397d385..5fd662fa0496c9ad545d691553b861a9b77b256d 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;
@@ -183,10 +190,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 +207,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);
 
@@ -219,8 +230,8 @@ NineSurface9_dtor( struct NineSurface9 *This )
     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,21 +243,33 @@ 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
@@ -479,13 +502,22 @@ NineSurface9_LockRect( struct NineSurface9 *This,
                                                                   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)
@@ -732,6 +764,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 +800,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);
 }