C++ 将HLSL像素着色器应用于Win32屏幕捕获
一点背景:我正在尝试制作一个Windows(10)应用程序,使屏幕看起来像旧的CRT显示器、扫描线、模糊等等。我使用微软官方的这一点作为出发点:在这个阶段,我可以捕获一个窗口,并通过新的鼠标窗口显示它,就像它是原始窗口一样 我正在尝试使用通常被认为是最好的CRT着色器;这些文件以.cg格式提供。我使用cgc将它们传输到hlsl,然后使用fxc将hlsl文件编译为已编译的着色器字节码。我能够成功加载已编译的着色器并创建像素着色器。然后在d3d上下文中设置像素着色器。然后,我尝试将捕捉曲面帧复制到像素着色器资源,并设置创建的着色器资源。所有这些都是构建和运行的,但我在输出图像中看不到任何差异,也不确定如何继续。以下是相关代码。我不是C++开发者,我把它作为个人项目,我计划在开源之后,我有一个原始的工作版本。谢谢你的建议C++ 将HLSL像素着色器应用于Win32屏幕捕获,c++,shader,directx,hlsl,direct3d,C++,Shader,Directx,Hlsl,Direct3d,一点背景:我正在尝试制作一个Windows(10)应用程序,使屏幕看起来像旧的CRT显示器、扫描线、模糊等等。我使用微软官方的这一点作为出发点:在这个阶段,我可以捕获一个窗口,并通过新的鼠标窗口显示它,就像它是原始窗口一样 我正在尝试使用通常被认为是最好的CRT着色器;这些文件以.cg格式提供。我使用cgc将它们传输到hlsl,然后使用fxc将hlsl文件编译为已编译的着色器字节码。我能够成功加载已编译的着色器并创建像素着色器。然后在d3d上下文中设置像素着色器。然后,我尝试将捕捉曲面帧复制到像
SimpleCapture::SimpleCapture(
IDirect3DDevice const& device,
GraphicsCaptureItem const& item)
{
m_item = item;
m_device = device;
// Set up
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
d3dDevice->GetImmediateContext(m_d3dContext.put());
auto size = m_item.Size();
m_swapChain = CreateDXGISwapChain(
d3dDevice,
static_cast<uint32_t>(size.Width),
static_cast<uint32_t>(size.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
2);
// ADDED THIS
HRESULT hr1 = D3DReadFileToBlob(L"crt-royale-first-pass-ps_4_0.fxc", &ps_1_buffer);
HRESULT hr = d3dDevice->CreatePixelShader(
ps_1_buffer->GetBufferPointer(),
ps_1_buffer->GetBufferSize(),
nullptr,
&ps_1
);
m_d3dContext->PSSetShader(
ps_1,
nullptr,
0
);
// END OF ADDED CHANGES
// Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and frame size.
m_framePool = Direct3D11CaptureFramePool::Create(
m_device,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2,
size);
m_session = m_framePool.CreateCaptureSession(m_item);
m_lastSize = size;
m_frameArrived = m_framePool.FrameArrived(auto_revoke, { this, &SimpleCapture::OnFrameArrived });
}
void SimpleCapture::OnFrameArrived(
Direct3D11CaptureFramePool const& sender,
winrt::Windows::Foundation::IInspectable const&)
{
auto newSize = false;
{
auto frame = sender.TryGetNextFrame();
auto frameContentSize = frame.ContentSize();
if (frameContentSize.Width != m_lastSize.Width ||
frameContentSize.Height != m_lastSize.Height)
{
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
newSize = true;
m_lastSize = frameContentSize;
m_swapChain->ResizeBuffers(
2,
static_cast<uint32_t>(m_lastSize.Width),
static_cast<uint32_t>(m_lastSize.Height),
static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
0);
}
{
auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
com_ptr<ID3D11Texture2D> backBuffer;
check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
// ADDED THIS
D3D11_TEXTURE2D_DESC txtDesc = {};
txtDesc.MipLevels = txtDesc.ArraySize = 1;
txtDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
txtDesc.SampleDesc.Count = 1;
txtDesc.Usage = D3D11_USAGE_IMMUTABLE;
txtDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
ID3D11Texture2D *tex;
d3dDevice->CreateTexture2D(&txtDesc, NULL,
&tex);
frameSurface.copy_to(&tex);
d3dDevice->CreateShaderResourceView(
tex,
nullptr,
srv_1
);
auto texture = srv_1;
m_d3dContext->PSSetShaderResources(0, 1, texture);
// END OF ADDED CHANGES
m_d3dContext->CopyResource(backBuffer.get(), frameSurface.get());
}
}
DXGI_PRESENT_PARAMETERS presentParameters = { 0 };
m_swapChain->Present1(1, 0, &presentParameters);
... // Truncated
SimpleCapture::SimpleCapture(
IDirect3DDevice常量和设备,
GraphicsCaptureItem(项目常量和项目)
{
m_项目=项目;
m_装置=装置;
//设立
自动d3dDevice=GetDXGIInterfaceFromObject(m_设备);
d3dDevice->GetImmediateContext(m_d3dContext.put());
自动大小=m_item.size();
m_swapChain=CreateDXGISwapChain(
第三个缺点,
静态铸件(尺寸、宽度),
静态铸件(尺寸、高度),
静态强制转换(DirectXPixelFormat::B8G8R8A8UIntNormalized),
2);
//加上这个
HRESULT hr1=d3dreardfiletoblob(L“crt-royale-first-pass-ps_4_0.fxc”&ps_1_缓冲区);
HRESULT hr=d3dDevice->CreatePixelShader(
ps_1_buffer->GetBufferPointer(),
ps_1_buffer->GetBufferSize(),
nullptr,
&ps_1
);
m_d3dContext->PSSetShader(
ps_1,
nullptr,
0
);
//添加的更改结束
//创建帧池,定义像素格式(DXGI_格式_B8G8R8A8_UNORM)和帧大小。
m_framePool=Direct3D11CaptureFramePool::Create(
m_装置,
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2.
尺寸);
m_session=m_framePool.CreateCaptureSession(m_项);
m_lastSize=尺寸;
m_framearrized=m_framePool.framearrized(自动撤销,{this,&SimpleCapture::onframearrized});
}
void SimpleCapture::onframeArrized(
Direct3D11CaptureFramePool常量和发送方,
winrt::Windows::Foundation::IInspectable常量&)
{
自动新闻化=假;
{
自动帧=sender.TryGetNextFrame();
auto-frameContentSize=frame.ContentSize();
如果(frameContentSize.Width!=m_lastSize.Width||
frameContentSize.Height!=m_lastSize.Height)
{
//我们捕获的东西已经改变了大小。
//我们需要先调整交换链的大小,然后对像素进行blit。
//完成后,退出帧,然后重新创建帧池。
newSize=true;
m_lastSize=frameContentSize;
m_swapChain->ResizeBuffers(
2.
静态浇铸(m_lastSize.宽度),
静态浇铸(m_lastSize.高度),
静态强制转换(DirectXPixelFormat::B8G8R8A8UIntNormalized),
0);
}
{
auto frameSurface=GetDXGIInterfaceFromObject(frame.Surface());
com_ptr backBuffer;
检查结果(m_swapChain->GetBuffer(0,guid_of(),backBuffer.put_void());
//加上这个
D3D11_TEXTURE2D_DESC txtDesc={};
txtDesc.MipLevels=txtDesc.ArraySize=1;
txtDesc.Format=DXGI_Format_B8G8R8A8_UNORM;
txtDesc.SampleDesc.Count=1;
txtDesc.Usage=D3D11\u Usage\u不可变;
txtDesc.BindFlags=D3D11\u BIND\u SHADER\u资源;
自动d3dDevice=GetDXGIInterfaceFromObject(m_设备);
ID3D11Texture2D*tex;
d3dDevice->CreateTexture2D(&txtDesc),NULL,
&特克斯);
frameSurface.将_复制到(&tex);
d3dDevice->CreateShaderResourceView(
特克斯,
nullptr,
srv_1
);
自动纹理=srv_1;
m_d3dContext->PSSetShaderResources(0,1,纹理);
//添加的更改结束
m_d3dContext->copyrource(backBuffer.get(),frameSurface.get());
}
}
DXGI_PRESENT_PARAMETERS presentParameters={0};
m_swapChain->Present1(1、0和presentParameters);
…//截断
着色器定义了事物的绘制方式。但是,您不绘制任何东西,只需复制,这就是着色器不执行任何操作的原因
您应该做的是删除CopyResource调用,而是在后缓冲区上绘制一个全屏四边形(这需要您创建一个可以绑定的顶点缓冲区,然后将后缓冲区设置为渲染目标,最后调用draw/DrawIndexed以实际渲染某些内容,然后调用着色器)
此外,由于我不确定您是否已经执行了此操作,并且只是从显示的代码中删除了它-CreatePixelShader之类的函数不会返回HRESULT只是为了好玩-您应该检查实际返回的内容,因为DirectX会以静默方式返回大多数错误,并希望您处理它们,而不是使程序崩溃。着色器定义事物的绘制方式。但是,你不绘制任何东西,你只是复制,这就是为什么着色器不做任何事情 您应该做的是删除CopyResource调用,而是在后缓冲区上绘制一个全屏四边形(这需要您创建一个可以绑定的顶点缓冲区,然后将后缓冲区设置为渲染目标,最后调用draw/DrawIndexed以实际渲染某些内容,然后调用着色器) 此外,由于我不确定您是否已经执行了此操作,并且只是从显示的代码中删除了它-CreatePixelShader之类的函数不会返回HRESULT只是为了好玩-您应该检查实际返回的内容,因为DirectX会以静默方式返回大多数错误,并希望您处理它们,而不是使程序崩溃