From 60624be2033f06b414cf76794c2f3b061dc28332 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 22 Sep 2016 17:03:17 +0200 Subject: [PATCH] st/nine: Implement MSAA quality levels 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 Signed-off-by: Axel Davy --- 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 fbbc586204a..09bfa3989ff 100644 --- a/src/gallium/state_trackers/nine/adapter9.c +++ b/src/gallium/state_trackers/nine/adapter9.c @@ -400,17 +400,31 @@ NineAdapter9_CheckDeviceMultiSampleType( struct NineAdapter9 *This, else /* render-target */ 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 50565b876dd..47fd3a48b55 100644 --- a/src/gallium/state_trackers/nine/device9.c +++ b/src/gallium/state_trackers/nine/device9.c @@ -1653,7 +1653,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"); @@ -1826,6 +1827,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 bbb148db66c..df3b38245c0 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 66c75812c15..ed3c821f337 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 ffa8c2af1bd..dc31bb93786 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 a83e8dd4c71..476bc81557a 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 fcda9c7837e..86c9be66ae6 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; @@ -239,7 +251,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; @@ -279,7 +291,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, @@ -297,6 +309,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); @@ -336,7 +349,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, @@ -362,6 +375,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.30.2