[Mesa-dev] [PATCH 67/75] st/nine: Implement MSAA quality levels

Axel Davy axel.davy at ens.fr
Wed Oct 5 20:09:40 UTC 2016


From: Patrick Rudolph <siro at das-labor.org>

Advertise quality levels:
Each supported multisample count matches to one quality level.
The application doesn't know how much samples each quality level has.
For that reason it's not possible to set the multisample mask.

Return errors on quality level missmatch.

Fixes several old games not having multisample support until now.

Fix for issue #73.

Signed-off-by: Patrick Rudolph <siro at das-labor.org>
Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
 src/gallium/state_trackers/nine/adapter9.c   | 20 ++++++++--
 src/gallium/state_trackers/nine/device9.c    |  8 +++-
 src/gallium/state_trackers/nine/nine_pipe.h  | 55 ++++++++++++++++++++++++++++
 src/gallium/state_trackers/nine/nine_state.c |  6 ++-
 src/gallium/state_trackers/nine/surface9.c   | 17 ++++++++-
 src/gallium/state_trackers/nine/surface9.h   |  7 ++++
 src/gallium/state_trackers/nine/swapchain9.c | 24 +++++++++---
 7 files changed, 125 insertions(+), 12 deletions(-)

diff --git a/src/gallium/state_trackers/nine/adapter9.c b/src/gallium/state_trackers/nine/adapter9.c
index fbbc586..09bfa39 100644
--- a/src/gallium/state_trackers/nine/adapter9.c
+++ b/src/gallium/state_trackers/nine/adapter9.c
@@ -401,16 +401,30 @@ NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This,
         bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
 
     pf = d3d9_to_pipe_format_checked(screen, SurfaceFormat, PIPE_TEXTURE_2D,
+                                     0, PIPE_BIND_SAMPLER_VIEW, FALSE, FALSE);
+
+    if (pf == PIPE_FORMAT_NONE && SurfaceFormat != D3DFMT_NULL) {
+        DBG("%s not available.\n", d3dformat_to_string(SurfaceFormat));
+        return D3DERR_INVALIDCALL;
+    }
+
+    pf = d3d9_to_pipe_format_checked(screen, SurfaceFormat, PIPE_TEXTURE_2D,
                                      MultiSampleType, bind, FALSE, FALSE);
 
-    if (pf == PIPE_FORMAT_NONE) {
+    if (pf == PIPE_FORMAT_NONE && SurfaceFormat != D3DFMT_NULL) {
         DBG("%s with %u samples not available.\n",
             d3dformat_to_string(SurfaceFormat), MultiSampleType);
         return D3DERR_NOTAVAILABLE;
     }
 
-    if (pQualityLevels)
-        *pQualityLevels = 1; /* gallium doesn't have quality levels */
+    if (pQualityLevels) {
+        /* NONMASKABLE MultiSampleType might have more than one quality level,
+         * while MASKABLE MultiSampleTypes have only one level.
+         * Advertise quality levels and map each level to a sample count. */
+         (void ) d3dmultisample_type_check(screen, SurfaceFormat,
+                 &MultiSampleType, D3DMULTISAMPLE_16_SAMPLES, pQualityLevels);
+         DBG("advertising %u quality levels\n", *pQualityLevels);
+    }
 
     return D3D_OK;
 }
diff --git a/src/gallium/state_trackers/nine/device9.c b/src/gallium/state_trackers/nine/device9.c
index 151f41e..eda4c78 100644
--- a/src/gallium/state_trackers/nine/device9.c
+++ b/src/gallium/state_trackers/nine/device9.c
@@ -1650,7 +1650,8 @@ NineDevice9_StretchRect( struct NineDevice9 *This,
         clamped = !!xy;
     }
 
-    ms = (dst->desc.MultiSampleType | 1) != (src->desc.MultiSampleType | 1);
+    ms = (dst->desc.MultiSampleType != src->desc.MultiSampleType) ||
+         (dst->desc.MultiSampleQuality != src->desc.MultiSampleQuality);
 
     if (clamped || scaled || (blit.dst.format != blit.src.format) || ms) {
         DBG("using pipe->blit()\n");
@@ -1823,6 +1824,11 @@ NineDevice9_SetRenderTarget( struct NineDevice9 *This,
         This->state.scissor.maxy = rt->desc.Height;
 
         This->state.changed.group |= NINE_STATE_VIEWPORT | NINE_STATE_SCISSOR | NINE_STATE_MULTISAMPLE;
+
+        if (This->state.rt[0] &&
+            (This->state.rt[0]->desc.MultiSampleType == D3DMULTISAMPLE_NONMASKABLE) !=
+            (rt->desc.MultiSampleType == D3DMULTISAMPLE_NONMASKABLE))
+            This->state.changed.group |= NINE_STATE_SAMPLE_MASK;
     }
 
     if (This->state.rt[i] != NineSurface9(pRenderTarget)) {
diff --git a/src/gallium/state_trackers/nine/nine_pipe.h b/src/gallium/state_trackers/nine/nine_pipe.h
index bbb148d..df3b382 100644
--- a/src/gallium/state_trackers/nine/nine_pipe.h
+++ b/src/gallium/state_trackers/nine/nine_pipe.h
@@ -348,6 +348,61 @@ d3d9_to_pipe_format_checked(struct pipe_screen *screen,
     return PIPE_FORMAT_NONE;
 }
 
+/* The quality levels are vendor dependent, so we set our own.
+ * Every quality level has its own sample count and sample
+ * position matrix.
+ * The exact mapping might differ from system to system but thats OK,
+ * as there's no way to gather more information about quality levels
+ * in D3D9.
+ * In case of NONMASKABLE multisample map every quality-level
+ * to a MASKABLE MultiSampleType:
+ *  0: no MSAA
+ *  1: 2x MSAA
+ *  2: 4x MSAA
+ *  ...
+ *  If the requested quality level is not available to nearest
+ *  matching quality level is used.
+ *  If no multisample is available the function sets
+ *  multisample to D3DMULTISAMPLE_NONE and returns zero.
+ */
+static inline HRESULT
+d3dmultisample_type_check(struct pipe_screen *screen,
+                          D3DFORMAT format,
+                          D3DMULTISAMPLE_TYPE *multisample,
+                          DWORD multisamplequality,
+                          DWORD *levels)
+{
+    unsigned bind, i;
+
+    assert(multisample);
+
+    if (levels)
+        *levels = 1;
+
+    if (*multisample == D3DMULTISAMPLE_NONMASKABLE) {
+        if (depth_stencil_format(format))
+            bind = d3d9_get_pipe_depth_format_bindings(format);
+        else /* render-target */
+            bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+
+        *multisample = 0;
+        for (i = D3DMULTISAMPLE_2_SAMPLES; i < D3DMULTISAMPLE_16_SAMPLES &&
+            multisamplequality; ++i) {
+            if (d3d9_to_pipe_format_checked(screen, format, PIPE_TEXTURE_2D,
+                    i, bind, FALSE, FALSE) != PIPE_FORMAT_NONE) {
+                multisamplequality--;
+                if (levels)
+                    (*levels)++;
+                *multisample = i;
+            }
+        }
+    }
+    /* Make sure to get an exact match */
+    if (multisamplequality)
+        return D3DERR_INVALIDCALL;
+    return D3D_OK;
+}
+
 static inline const char *
 d3dformat_to_string(D3DFORMAT fmt)
 {
diff --git a/src/gallium/state_trackers/nine/nine_state.c b/src/gallium/state_trackers/nine/nine_state.c
index 66c7581..ed3c821 100644
--- a/src/gallium/state_trackers/nine/nine_state.c
+++ b/src/gallium/state_trackers/nine/nine_state.c
@@ -1088,7 +1088,11 @@ nine_update_state(struct NineDevice9 *device)
             pipe->set_blend_color(pipe, &color);
         }
         if (group & NINE_STATE_SAMPLE_MASK) {
-            pipe->set_sample_mask(pipe, state->rs[D3DRS_MULTISAMPLEMASK]);
+            if (state->rt[0]->desc.MultiSampleType == D3DMULTISAMPLE_NONMASKABLE) {
+                pipe->set_sample_mask(pipe, ~0);
+            } else {
+                pipe->set_sample_mask(pipe, state->rs[D3DRS_MULTISAMPLEMASK]);
+            }
         }
         if (group & NINE_STATE_STENCIL_REF) {
             struct pipe_stencil_ref ref;
diff --git a/src/gallium/state_trackers/nine/surface9.c b/src/gallium/state_trackers/nine/surface9.c
index ffa8c2a..dc31bb9 100644
--- a/src/gallium/state_trackers/nine/surface9.c
+++ b/src/gallium/state_trackers/nine/surface9.c
@@ -58,6 +58,7 @@ NineSurface9_ctor( struct NineSurface9 *This,
     struct pipe_surface *surf;
     struct pipe_context *pipe = pParams->device->pipe;
     bool allocate = !pContainer && pDesc->Format != D3DFMT_NULL;
+    D3DMULTISAMPLE_TYPE multisample_type;
 
     DBG("This=%p pDevice=%p pResource=%p Level=%u Layer=%u pDesc=%p\n",
         This, pParams->device, pResource, Level, Layer, pDesc);
@@ -82,6 +83,18 @@ NineSurface9_ctor( struct NineSurface9 *This,
 
     This->data = (uint8_t *)user_buffer;
 
+    multisample_type = pDesc->MultiSampleType;
+
+    /* Map MultiSampleQuality to MultiSampleType */
+    hr = d3dmultisample_type_check(pParams->device->screen,
+                                   pDesc->Format,
+                                   &multisample_type,
+                                   pDesc->MultiSampleQuality,
+                                   NULL);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
     /* TODO: this is (except width and height) duplicate from
      * container info (in the pContainer case). Some refactoring is
      * needed to avoid duplication */
@@ -92,7 +105,7 @@ NineSurface9_ctor( struct NineSurface9 *This,
     This->base.info.depth0 = 1;
     This->base.info.last_level = 0;
     This->base.info.array_size = 1;
-    This->base.info.nr_samples = pDesc->MultiSampleType;
+    This->base.info.nr_samples = multisample_type;
     This->base.info.usage = PIPE_USAGE_DEFAULT;
     This->base.info.bind = PIPE_BIND_SAMPLER_VIEW; /* StretchRect */
 
@@ -721,7 +734,7 @@ NineSurface9_SetResourceResize( struct NineSurface9 *This,
 
     This->desc.Width = This->base.info.width0 = resource->width0;
     This->desc.Height = This->base.info.height0 = resource->height0;
-    This->desc.MultiSampleType = This->base.info.nr_samples = resource->nr_samples;
+    This->base.info.nr_samples = resource->nr_samples;
 
     This->stride = nine_format_get_stride(This->base.info.format,
                                           This->desc.Width);
diff --git a/src/gallium/state_trackers/nine/surface9.h b/src/gallium/state_trackers/nine/surface9.h
index a83e8dd..476bc81 100644
--- a/src/gallium/state_trackers/nine/surface9.h
+++ b/src/gallium/state_trackers/nine/surface9.h
@@ -116,6 +116,13 @@ NineSurface9_SetResource( struct NineSurface9 *This,
     pipe_surface_reference(&This->surface[1], NULL);
 }
 
+static inline void
+NineSurface9_SetMultiSampleType( struct NineSurface9 *This,
+                                 D3DMULTISAMPLE_TYPE mst )
+{
+    This->desc.MultiSampleType = mst;
+}
+
 void
 NineSurface9_SetResourceResize( struct NineSurface9 *This,
                                 struct pipe_resource *resource );
diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c
index ccc6511..a811936 100644
--- a/src/gallium/state_trackers/nine/swapchain9.c
+++ b/src/gallium/state_trackers/nine/swapchain9.c
@@ -120,6 +120,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
     BOOL has_present_buffers = FALSE;
     int depth;
     unsigned i, oldBufferCount, newBufferCount;
+    D3DMULTISAMPLE_TYPE multisample_type;
 
     DBG("This=%p pParams=%p\n", This, pParams);
     user_assert(pParams != NULL, E_POINTER);
@@ -204,15 +205,26 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
     newBufferCount = pParams->BackBufferCount +
                      (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
 
+    multisample_type = pParams->MultiSampleType;
+
+    /* Map MultiSampleQuality to MultiSampleType */
+    hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat,
+                                   &multisample_type,
+                                   pParams->MultiSampleQuality,
+                                   NULL);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
     pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat,
-                                     PIPE_TEXTURE_2D, pParams->MultiSampleType,
+                                     PIPE_TEXTURE_2D, multisample_type,
                                      PIPE_BIND_RENDER_TARGET, FALSE, FALSE);
 
     if (This->actx->linear_framebuffer ||
         (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
         pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
         pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
-        pParams->MultiSampleType >= 2 ||
+        multisample_type >= 2 ||
         (This->actx->ref && This->actx->ref == This->screen))
         has_present_buffers = TRUE;
 
@@ -238,7 +250,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
     desc.Type = D3DRTYPE_SURFACE;
     desc.Pool = D3DPOOL_DEFAULT;
     desc.MultiSampleType = pParams->MultiSampleType;
-    desc.MultiSampleQuality = 0;
+    desc.MultiSampleQuality = pParams->MultiSampleQuality;
     desc.Width = pParams->BackBufferWidth;
     desc.Height = pParams->BackBufferHeight;
 
@@ -278,7 +290,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
 
     for (i = 0; i < newBufferCount; ++i) {
         tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
-        tmplt.nr_samples = pParams->MultiSampleType;
+        tmplt.nr_samples = multisample_type;
         if (!has_present_buffers)
             tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS;
         tmplt.format = d3d9_to_pipe_format_checked(This->screen,
@@ -296,6 +308,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
         if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
             resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
         if (This->buffers[i]) {
+            NineSurface9_SetMultiSampleType(This->buffers[i], desc.MultiSampleType);
             NineSurface9_SetResourceResize(This->buffers[i], resource);
             if (has_present_buffers)
                 pipe_resource_reference(&resource, NULL);
@@ -335,7 +348,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
          * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support
          * would fail too, so we are fine. */
         tmplt.bind |= PIPE_BIND_SAMPLER_VIEW;
-        tmplt.nr_samples = pParams->MultiSampleType;
+        tmplt.nr_samples = multisample_type;
         tmplt.format = d3d9_to_pipe_format_checked(This->screen,
                                                    pParams->AutoDepthStencilFormat,
                                                    PIPE_TEXTURE_2D,
@@ -361,6 +374,7 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
             return D3DERR_OUTOFVIDEOMEMORY;
         }
         if (This->zsbuf) {
+            NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType);
             NineSurface9_SetResourceResize(This->zsbuf, resource);
             pipe_resource_reference(&resource, NULL);
         } else {
-- 
2.10.0



More information about the mesa-dev mailing list