Улучшить качество образца текстуры в Direct3D - PullRequest
0 голосов
/ 26 апреля 2018

Я использую 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 рендеринг Это GDI способ и масштабирование изображения самостоятельно: рендер рендеринга Мы видим, что особенно тексты нечеткие.

1 Ответ

0 голосов
/ 27 апреля 2018

Одна вещь, которую вы, возможно, захотите рассмотреть, - это создание цепочки MIP для рассматриваемой текстуры, так как ваше состояние фильтрации D3D11_FILTER_MIN_MAG_MIP_LINEAR (которое является лучшим вариантом для вашего использования) будет использовать уровни MIP текстуры.

Количество мипов должно быть в пределах 1 + log2(max(width, height)), но в зависимости от минимального размера дисплея вы можете использовать меньше мипов.Затем установите textureDesc.MiscFlags, чтобы включить флаг D3D11_RESOURCE_MISC_GENERATE_MIPS, и убедитесь, что элемент BindFlags включает D3D11_BIND_SHADER_RESOURCE и D3D11_BIND_RENDER_TARGET.Затем, заполнив содержимое текстуры (после Unmap), вы можете вызвать ID3D11DeviceContext::GenerateMips() в ближайшем контексте.

Обратите внимание, что флаги привязки и generate-mip не будут работать на динамическом ресурсе, поэтому выВам нужно будет сохранить исходную динамическую текстуру как есть и добавить вторую текстуру, помеченную как D3D11_USAGE_DEFAULT с уровнями> 1 mip и другими флагами, указанными выше.Затем, когда вы закончите заполнение промежуточной (динамической) текстуры, вызовите ID3D11DeviceContext::CopyResource, чтобы скопировать в новую текстуру.Вы бы тоже указали свой ресурс шейдера на этого нового парня.

Это может немного помочь, но все равно будет не так хорошо, как действительно высококачественный фильтр уменьшения масштаба.

...