Reputation: 13
I'm using directx 11 to render video.I create a Texture2D and copy rgba video data into it.Also it is the resource of pixel shader.Here is code:
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);
}
Here is how I create swap chain and set render target:
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);
}
I've set sample state for device context:
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);
}
My pixel shader is very simple:
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;
}
My problem is how to improve the render quality when the size of window displaying video is smaller than the size of video.At this time, shaderTexture.Sample in pixel shader is the key point.But I have no idea how to get better sample result.I've trie to change parameter for sample state and it didn't work.I'm not familiar with DirectX.So did I miss something? PS:I have tow pictures for contrast. This one is d3d way: DirectX render This one is gdi way and scaling image myself: gdi render We can see that especially texts are fuzzy.
Upvotes: 0
Views: 1161
Reputation: 768
One thing you may want to look into is generating a mip chain for the texture in question, since your D3D11_FILTER_MIN_MAG_MIP_LINEAR
filtering state (which is the best option for your usage) will leverage the mip levels of the texture.
The mip count should be along the lines of 1 + log2(max(width, height))
, but depending on the minimum display size you can use fewer mips. Then set the textureDesc.MiscFlags
to include the D3D11_RESOURCE_MISC_GENERATE_MIPS
flag, and make sure the BindFlags
member includes D3D11_BIND_SHADER_RESOURCE
and D3D11_BIND_RENDER_TARGET
. Then once you've filled the texture contents (after Unmap) you can call ID3D11DeviceContext::GenerateMips()
on the immediate context.
Note that the binding and generate-mip flags won't work on a dynamic resource, so you'll need to keep your original, dynamic texture as-is, and add a second texture that's marked as D3D11_USAGE_DEFAULT
with the >1 mip levels and the other flags specified above. Then once you've finished filling the staging (dynamic) texture, call ID3D11DeviceContext::CopyResource
to copy to the new texture. You'd make your shader resource view point to this new guy too.
This may help a little, but it still won't be as good as a really high-quality down-scale filter.
Upvotes: 2