Улучшить качество образца текстуры в Direct3D
Я использую 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. Образец в пиксельном шейдере. Но я понятия не имею, как получить лучший результат выборки. Я пытался изменить параметр для образца состояния, и он не работал. Я не знаком с DirectX. Так я что-то пропустил? PS: у меня есть буксирные картинки для контраста. Это способ d3d: визуализация DirectX. Это способ gdi и масштабирование изображения самостоятельно: рендер gdi. Мы можем видеть, что тексты нечеткие.
1 ответ
Одна вещь, которую вы, возможно, захотите рассмотреть, - это создание цепочки 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
скопировать на новую текстуру. Вы бы тоже указали свой ресурс шейдера на этого нового парня.
Это может немного помочь, но все равно будет не так хорошо, как действительно качественный фильтр уменьшения масштаба.