Multisampling with directX and UWP

  antialiasing, c++, directx, uwp

I’m trying to enable multisampling in my application. I found and followed this article: Line drawing and anti-aliasing. When I got to the multisampling part, I read that:

The ability to create an MSAA DXGI swap chain is only supported for the older "bit-blt" style presentation modes, specifically DXGI_SWAP_EFFECT_DISCARD or DXGI_SWAP_EFFECT_SEQUENTIAL. The newer "flip" style presentation modes DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD required for Universal Windows Platform (UWP) apps don’t support creating MSAA swap chains. Instead, you create your own MSAA render target and then explicitly resolve from MSAA to single-sample via ResolveSubresource to the DXGI back-buffer for presentation.

I was then directed to an another site Multisampling in Universal Windows Platform (UWP) apps. I followed the article but still no results. I found the SimpleMSAA_PC sample code and compared my code with it but again no results.

In my application I’m using the Line drawing example from the first article and in the CreateResources function I wrote:

void Game::CreateResources()
{
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews [] = { nullptr };
m_d3dContext->OMSetRenderTargets(static_cast<UINT>(std::size(nullViews)), nullViews, nullptr);
m_renderTargetView.Reset();
m_depthStencilView.Reset();
m_d3dContext->Flush();

const UINT backBufferWidth = static_cast<UINT>(m_outputWidth);
const UINT backBufferHeight = static_cast<UINT>(m_outputHeight);
const DXGI_FORMAT backBufferFormat = c_backBufferFormat;
const DXGI_FORMAT depthBufferFormat = c_depthBufferFormat;
constexpr UINT backBufferCount = 2;

// If the swap chain already exists, resize it, otherwise create one.
if (m_swapChain)
{
    HRESULT hr = m_swapChain->ResizeBuffers(backBufferCount, backBufferWidth, backBufferHeight, backBufferFormat, 0);

    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
    {
        // If the device was removed for any reason, a new device and swap chain will need to be created.
        OnDeviceLost();

        // Everything is set up now. Do not continue execution of this method. OnDeviceLost will reenter this method
        // and correctly set up the new device.
        return;
    }
    else
    {
        DX::ThrowIfFailed(hr);
    }
}
else
{
    // First, retrieve the underlying DXGI Device from the D3D Device.
    ComPtr<IDXGIDevice1> dxgiDevice;
    DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(dxgiDevice->GetAdapter(dxgiAdapter.GetAddressOf()));

    // And obtain the factory object that created it.
    ComPtr<IDXGIFactory2> dxgiFactory;
    DX::ThrowIfFailed(dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.GetAddressOf())));

    // Create a descriptor for the swap chain.
    DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
    swapChainDesc.Width = backBufferWidth;
    swapChainDesc.Height = backBufferHeight;
    swapChainDesc.Format = backBufferFormat;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = backBufferCount;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    swapChainDesc.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
    swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;

    ComPtr<IDXGISwapChain1> swapChain;
    DX::ThrowIfFailed(dxgiFactory->CreateSwapChainForCoreWindow(
        m_d3dDevice.Get(),
        m_window,
        &swapChainDesc,
        nullptr,
        swapChain.GetAddressOf()
        ));

    DX::ThrowIfFailed(swapChain.As(&m_swapChain));

    DX::ThrowIfFailed(dxgiDevice->SetMaximumFrameLatency(1));
}

DX::ThrowIfFailed(m_swapChain->SetRotation(m_outputRotation));


// TODO: Initialize windows-size dependent objects here.
m_view = Matrix::CreateLookAt(Vector3(2.f, 2.f, 2.f),
    Vector3::Zero, Vector3::UnitY);
m_proj = Matrix::CreatePerspectiveFieldOfView(XM_PI / 4.f,
    float(backBufferWidth) / float(backBufferHeight), 0.1f, 10.f);

m_effect->SetView(m_view);
m_effect->SetProjection(m_proj);



CD3D11_TEXTURE2D_DESC renderTargetDesc(
    c_backBufferFormat,
    backBufferWidth,
    backBufferHeight,
    1, // The render target view has only one texture.
    1, // Use a single mipmap level.
    D3D11_BIND_RENDER_TARGET,
    D3D11_USAGE_DEFAULT,
    0,
    4
);

// Create a surface that's multisampled.
DX::ThrowIfFailed(
    m_d3dDevice->CreateTexture2D(
        &renderTargetDesc,
        nullptr,
        &m_msaaRenderTarget)
);

// Create a render target view. 
CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DMS, c_backBufferFormat);
DX::ThrowIfFailed(
    m_d3dDevice->CreateRenderTargetView(
        m_msaaRenderTarget.Get(),
        &renderTargetViewDesc,
        &m_d3dRenderTargetView
    )
);

// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
    c_depthBufferFormat,
    backBufferWidth,
    backBufferHeight,
    1, // This depth stencil view has only one texture.
    1, // Use a single mipmap level.
    D3D11_BIND_DEPTH_STENCIL,
    D3D11_USAGE_DEFAULT,
    0,
    4
);

ComPtr<ID3D11Texture2D> depthStencil;
DX::ThrowIfFailed(
    m_d3dDevice->CreateTexture2D(
        &depthStencilDesc,
        nullptr,
        &depthStencil
    )
);

CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2DMS, c_depthBufferFormat);
DX::ThrowIfFailed(
    m_d3dDevice->CreateDepthStencilView(
        depthStencil.Get(),
        nullptr,
        m_depthStencilView.ReleaseAndGetAddressOf()
    )
);

m_screenViewport = CD3D11_VIEWPORT(
    0.0f,
    0.0f,
    backBufferWidth,
    backBufferHeight
);

m_d3dContext->RSSetViewports(1, &m_screenViewport);
}

And in render I handle it like this

void Game::Render()
{
// Don't try to render anything before the first Update.
if (m_timer.GetFrameCount() == 0)
{
    return;
}

Clear();

// TODO: Add your rendering code here.

m_d3dContext->OMSetBlendState(m_states->Opaque(), nullptr, 0xFFFFFFFF);
m_d3dContext->OMSetDepthStencilState(m_states->DepthNone(), 0);

m_effect->SetWorld(m_world);

m_effect->Apply(m_d3dContext.Get());

m_d3dContext->IASetInputLayout(m_inputLayout.Get());

m_batch->Begin();

Vector3 xaxis(2.f, 0.f, 0.f);
Vector3 yaxis(0.f, 0.f, 2.f);
Vector3 origin = Vector3::Zero;

size_t divisions = 20;

for (size_t i = 0; i <= divisions; ++i)
{
    float fPercent = float(i) / float(divisions);
    fPercent = (fPercent * 2.0f) - 1.0f;

    Vector3 scale = xaxis * fPercent + origin;

    VertexPositionColor v1(scale - yaxis, Colors::White);
    VertexPositionColor v2(scale + yaxis, Colors::White);
    m_batch->DrawLine(v1, v2);
}

for (size_t i = 0; i <= divisions; i++)
{
    float fPercent = float(i) / float(divisions);
    fPercent = (fPercent * 2.0f) - 1.0f;

    Vector3 scale = yaxis * fPercent + origin;

    VertexPositionColor v1(scale - xaxis, Colors::White);
    VertexPositionColor v2(scale + xaxis, Colors::White);
    m_batch->DrawLine(v1, v2);
}

m_batch->End();

ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(m_swapChain->GetBuffer(0, IID_PPV_ARGS(backBuffer.GetAddressOf())));

m_d3dContext->ResolveSubresource(backBuffer.Get(), 0, m_msaaRenderTarget.Get(), 0, c_backBufferFormat);

Present();
}

For formats I use those two constants

const DXGI_FORMAT c_backBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
const DXGI_FORMAT c_depthBufferFormat = DXGI_FORMAT_D32_FLOAT;

Current result:

Current result

What am I doing wrong?

Source: Windows Questions C++

LEAVE A COMMENT