【问题标题】:Improve the quality of texture sample in Direct3D提高 Direct3D 中纹理样本的质量
【发布时间】:2018-04-28 10:54:17
【问题描述】:

我正在使用directx 11渲染视频。我创建了一个Texture2D并将rgba视频数据复制到其中。它也是像素着色器的资源。这里是代码:

void CreateTexture(int nWidth, int nHeight)
{
    D3D11_TEXTURE2D_DESC textureDesc;
    textureDesc.Width = nWidth;//Video width
    textureDesc.Height = nHeight;//Video height
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    textureDesc.SampleDesc.Count = 1;
    textureDesc.Usage = D3D11_USAGE_DYNAMIC;
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    textureDesc.MiscFlags = 0;
    m_pD3dDevice->CreateTexture2D(&textureDesc, NULL, &m_pRGBATexture);

    D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
    ZeroMemory(&shaderResourceViewDesc, 
               sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
    shaderResourceViewDesc.Format = textureDesc.Format;
    shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
    shaderResourceViewDesc.Texture2D.MipLevels = 1;
    m_pD3dDevice->CreateShaderResourceView(m_pRGBATexture, &shaderResourceViewDesc, &m_pRGBAShaderResouceView);

    ID3D11ShaderResourceView* pArrResources[] = {m_pRGBAShaderResouceView};
    m_pD3dDeviceContext->PSSetShaderResources(0, 1, &pArrShaderResourceView[0]);
}

void WriteVideoData(BYTE *pData, DWORD nSize)
{
    D3D11_MAPPED_SUBRESOURCE textureResource;
    ZeroMemory(&textureResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
    hr = m_pD3dDeviceContext->Map(m_pRGBATexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &textureResource);
    FAIL_RETURN_FALSE("Fail to map rgba texture resource.");
    BYTE *pMappedData = reinterpret_cast<BYTE*>(textureResource.pData);
    BYTE *pTmpBuffer = pFrameBuffer;
    for (int i = 0; i < nHeight; ++i)
    {
        CopyMemory(pMappedData, pTmpBuffer, nWidth * 4);
        pMappedData += rgbaTextureResource.RowPitch;
        pTmpBuffer += nWidth * 4;
    }
    m_pD3dDeviceContext->Unmap(m_pRGBATexture, 0);
}

这是我如何创建交换链和设置渲染目标:

void InitSwapChain(int nWidth, int nHeight)//Displayed window size
{
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
    swapChainDesc.BufferDesc.Width = nWidth;
    swapChainDesc.BufferDesc.Height = nHeight;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.OutputWindow = m_hWnd;
    swapChainDesc.Windowed = true;

    IDXGIDevice * dxgiDevice = NULL;
    hr = m_pD3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice);
    FAIL_RETURN_FALSE("Fail to Query IDXGIDevice");

    IDXGIAdapter * dxgiAdapter = NULL;
    hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&dxgiAdapter);
    SAFE_RELEASE(dxgiDevice);
    FAIL_RETURN_FALSE("Fail to Query IDXGIAdapter");

    IDXGIFactory * dxgiFactory = NULL;
    hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&dxgiFactory);
    SAFE_RELEASE(dxgiAdapter);
    FAIL_RETURN_FALSE("Fail to Query IDXGIFactory");

    hr = dxgiFactory->CreateSwapChain(m_pD3dDevice, &swapChainDesc, &m_pSwapChain);
    FAIL_RETURN_FALSE("Fail to create swap chain");
    ID3D11Texture2D *pBackBuffer = NULL;
    m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    hr = m_pD3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &m_pBackBufferTargetView);
    m_pD3dDeviceContext->OMSetRenderTargets(1, &m_pBackBufferTargetView, m_pDepthStencilView);
}

我已经为设备上下文设置了示例状态:

void SetSampleState()
{
    D3D11_SAMPLER_DESC samplerDesc;
    ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));

    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 16;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    HRESULT hr = m_pD3dDevice->CreateSamplerState(&samplerDesc, &m_pSamplerState);
    FAIL_RETURN_FALSE("Fail to create sampler state");

    m_pD3dDeviceContext->PSSetSamplers(0, 1, &m_pSamplerState);
}

我的像素着色器很简单:

Texture2D shaderTexture;
SamplerState SampleType;

struct PixelInputType
{
    float4 position : SV_POSITION;
    float4 blendingColor : COLOR;
    float2 tex : TEXCOORD0;
};

struct PiXelOutput
{
    float4 color : SV_TARGET;
};

PiXelOutput main(PixelInputType input)
{
    PiXelOutput output;
    float4 color = shaderTexture.Sample(SampleType, input.tex);
    output.color.x = color.z;
    output.color.y = color.y;
    output.color.z = color.x;
    output.color.w = 1.0;
    return output;
}

我的问题是当窗口显示视频的大小小于视频的大小时如何提高渲染质量。此时像素着色器中的shaderTexture.Sample是关键点。但是我不知道如何获得更好的样本结果。我尝试更改样本状态的参数,但没有成功。我不熟悉 DirectX。所以我错过了什么吗? PS:我有两张图片作为对比。 这是 d3d 方式: DirectX render 这是我自己的gdi方式和缩放图像: gdi render 我们可以看到,尤其是文本是模糊的。

【问题讨论】:

    标签: textures scale render direct3d


    【解决方案1】:

    您可能想要研究的一件事是为相关纹理生成一个 mip 链,因为您的 D3D11_FILTER_MIN_MAG_MIP_LINEAR 过滤状态(这是您使用的最佳选择)将利用纹理的 mip 级别。

    mip 计数应与1 + log2(max(width, height)) 一致,但根据最小显示尺寸,您可以使用更少的 mip。然后将textureDesc.MiscFlags 设置为包含D3D11_RESOURCE_MISC_GENERATE_MIPS 标志,并确保BindFlags 成员包含D3D11_BIND_SHADER_RESOURCED3D11_BIND_RENDER_TARGET。然后,一旦您填充了纹理内容(在 Unmap 之后),您就可以在直接上下文中调用 ID3D11DeviceContext::GenerateMips()

    请注意,绑定和 generate-mip 标志不适用于动态资源,因此您需要保持原始动态纹理不变,并添加标记为 D3D11_USAGE_DEFAULT 的第二个纹理>1 mip 级别和上面指定的其他标志。然后,一旦您完成了暂存(动态)纹理的填充,调用ID3D11DeviceContext::CopyResource 以复制到新纹理。你也会让你的着色器资源视图指向这个新人。

    这可能会有所帮助,但它仍然不如真正高质量的缩小过滤器。

    【讨论】:

    • 感谢您的回复。我已将 'MipLevels' 设置为 0(我也尝试过其他值)和标志,但在创建纹理时出现“E_INVALIDARG 一个或多个参数无效”。有什么问题吗?
    • 使用调试标志 (D3D11_CREATE_DEVICE_DEBUG) 创建设备,您应该在调试器的 D3D 调试输出中看到原因。
    • 实际上,再次查看您的代码,问题在于所讨论的纹理是作为动态资源创建的(这是有道理的,因为您是从 CPU 填充它)。遗憾的是,您不能将其用作渲染目标资源,这很可能是失败的原因。我会用更正来编辑我的答案:)
    • 它对我有用!是的,它仍然不如真正高质量的缩小过滤器,但要好得多。我正在尝试用 HLSL 重写缩小算法像素着色器以获得更好的效果。谢谢。
    猜你喜欢
    • 2023-04-05
    • 2011-06-22
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 2012-01-26
    • 2012-11-12
    • 1970-01-01
    相关资源
    最近更新 更多