В D2D я использую объект ID2D1RenderTarget для рисования линии и изображения в отдельных потоках, даже для рендеринга в другой объект ID2D1RenderTarget в том же потоке, он всегда работает нормально.
Но в случае необходимости поддержки многопоточный D3D / Media Foundation, я использую глобальный ID3D3d11Device и сделал взаимодействие D2D / D3D.
если работает только один поток, он работает хорошо; ошибка при одновременном запуске двух потоков (у каждого потока есть окно CDxRender), сообщалось об ошибке, я не знаю, как ее решить:
D2D DEBUG ERROR - An attempt to draw to an inaccessible target has been detected.
MFVerifDemo.exe возникает точка останова отладки
Then press F5, continue to run:
D3D11 ERROR: ID3D11DeviceContext::Draw: A Vertex Shader is always required when drawing, but none is currently bound. [ EXECUTION ERROR #341: DEVICE_DRAW_VERTEX_SHADER_NOT_SET]
D3D11 ERROR: ID3D11DeviceContext::Draw: Rasterization Unit is enabled (PixelShader is not NULL or Depth/Stencil test is enabled and RasterizedStream is not D3D11_SO_NO_RASTERIZED_STREAM) but position is not provided by the last shader before the Rasterization Unit. [ EXECUTION ERROR #362: DEVICE_DRAW_POSITION_NOT_PRESENT]
D3D11: Removing Device.
1 , Используйте d3d11createdevice для создания глобальной переменной _d3d11_device и упакуйте список executecommandlist:
CComPtr<id3d11device> _d3d11_device
HRESULT CreateD3DDevice(ID3D11Device** d3d11_device)
{
CComPtr<ID3D11DeviceContext> d3d11_immedContex;
//Describe our Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = 0;
bufferDesc.Height = 0;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//Create our _swap_chain1
HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE , NULL, D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_BGRA_SUPPORT, NULL, NULL, D3D11_SDK_VERSION, d3d11_device, NULL, &d3d11_immedContex);
RETURN_ON_FAIL(hr);
CComPtr<ID3D11Multithread> D3DDevMT;
hr = (*d3d11_device)->QueryInterface(IID_PPV_ARGS(&D3DDevMT));
RETURN_ON_FAIL(hr);
D3DDevMT->SetMultithreadProtected(TRUE);
return hr;
}
void ExecuteCommandList(CComPtr<ID3D11DeviceContext> deferred_context)
{
CComPtr<ID3D11CommandList> command_list;
HRESULT hr = deferred_context->FinishCommandList(FALSE, &command_list);
RETURN_ON_FAIL2(hr);
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d11_device->GetImmediateContext(&immediate_context);
if (immediate_context)
{
std::unique_lock <std::mutex> lck(_mutex);
immediate_context->ExecuteCommandList(command_list, FALSE);
}
}
2 , В классе окна "CDxRender" определяет серию переменных-членов:
const int Output_Width = 960;
const int Output_Height = 720;
const UINT32 fps = 50;
struct DefVertBuffer
{
DirectX::XMFLOAT3 pos;
DirectX::XMFLOAT4 color;
DirectX::XMFLOAT2 texCoord;
};
CComPtr<IDXGISwapChain1> _swap_chain1;
CComPtr<ID3D11DeviceContext> _deferred_context;
CComPtr<ID2D1Factory> _d2d_factory;
CComPtr<ID3D11RenderTargetView> _render_target_view;
CComPtr<ID3D11Texture2D> _back_texture2d;
CComPtr<IDXGISurface> _back_dxgi_surface;
CComPtr<ID2D1RenderTarget> _back_render_target;
CComPtr<ID2D1Bitmap> _back_d2d1_bitmap;
CComPtr<ID3D11SamplerState> _sampler_state;
CComPtr<ID3D11InputLayout> _input_layout;
CComPtr<ID3D11VertexShader> _vertex_shader;
CComPtr<ID3D11PixelShader> _pixel_shader;
CComPtr<ID3D11Buffer> _vert_buffer;
CComPtr<ID3D11Buffer> _index_buffer;
3 , Основная реализация выглядит следующим образом:
HRESULT CDxRender::InitD3d11()
{
RECT client_rect;
GetClientRect(&client_rect);
DirectX::XMMATRIX WVP;
WVP = DirectX::XMMatrixOrthographicOffCenterLH(0.0f, static_cast<float>(client_rect.right - client_rect.left), static_cast<float>(client_rect.bottom - client_rect.top), 0.0f, 0.1f, 100.0f);
//Create our _swap_chain1
CComPtr<IDXGIFactory2> dxgi_factory2;
HRESULT hr = GetDxgiFactoryFromD3DDevice(_d3d11_device, &dxgi_factory2);
RETURN_ON_FAIL(hr);
//Describe our _swap_chain1
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = client_rect.right - client_rect.left; // Match the size of the window.
swapChainDesc.Height = client_rect.bottom - client_rect.top;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
swapChainDesc.Flags = 0;
swapChainDesc.Scaling = DXGI_SCALING_NONE;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
hr = dxgi_factory2->CreateSwapChainForHwnd(_d3d11_device, m_hWnd, &swapChainDesc, nullptr, nullptr, &_swap_chain1);
RETURN_ON_FAIL(hr);
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, &_d2d_factory);
RETURN_ON_FAIL(hr);
hr = _d3d11_device->CreateDeferredContext(0, &_deferred_context);
RETURN_ON_FAIL(hr);
D3D11_BUFFER_DESC bufDs;
memset(&bufDs, 0, sizeof(bufDs));
bufDs.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufDs.Usage = D3D11_USAGE_DEFAULT;
bufDs.ByteWidth = sizeof(DefVertBuffer) * 4;
D3D11_SUBRESOURCE_DATA subData;
std::vector<DefVertBuffer> temptBuffer;
DefVertBuffer temptData;
// lb
temptData.pos = { -1.0f, -1.0f, 0.0f };
temptData.color = { 1.0f,0.0f,0.0f,1.0f };
temptData.texCoord = { 0.0f, 1.0f };
temptBuffer.push_back(temptData);
// lt
temptData.pos = { -1.0f,1.0f,0.0f };
temptData.color = { 1.0f,0.0f,0.0f,1.0f };
temptData.texCoord = { 0.0f, 0.0f };
temptBuffer.push_back(temptData);
// rt
temptData.pos = { 1.0f, 1.0f, 0.0f};
temptData.color = { 1.0f,0.0f,0.0f,1.0f };
temptData.texCoord = { 1.0f, 0.0f };
temptBuffer.push_back(temptData);
// rb
temptData.pos = { 1.0f, -1.0f, 0.0f };
temptData.color = { 1.0f,0.0f,0.0f,1.0f };
temptData.texCoord = { 1.0f, 1.0f };
temptBuffer.push_back(temptData);
subData.pSysMem = temptBuffer.data();
hr = _d3d11_device->CreateBuffer(&bufDs, &subData, &_vert_buffer);
RETURN_ON_FAIL(hr);
unsigned __int32 indexBuff[] =
{
0,1,2,
0,2,3
};
bufDs.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufDs.ByteWidth = sizeof(unsigned __int32) * 6;
subData.pSysMem = indexBuff;
hr = _d3d11_device->CreateBuffer(&bufDs, &subData, &_index_buffer);
RETURN_ON_FAIL(hr);
std::vector<D3D11_INPUT_ELEMENT_DESC> layout;
layout.push_back({ "POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 });
layout.push_back({ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 });
layout.push_back({ "TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,28,D3D11_INPUT_PER_VERTEX_DATA,0 });
hr = _d3d11_device->CreateInputLayout(layout.data(), layout.size(), g_VertexShader, ARRAYSIZE(g_VertexShader), &_input_layout);
RETURN_ON_FAIL(hr);
hr = _d3d11_device->CreateVertexShader(g_VertexShader, ARRAYSIZE(g_VertexShader), NULL, &_vertex_shader);
RETURN_ON_FAIL(hr);
hr = _d3d11_device->CreatePixelShader(g_PixelShader, ARRAYSIZE(g_PixelShader), NULL, &_pixel_shader);
RETURN_ON_FAIL(hr);
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.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = _d3d11_device->CreateSamplerState(&samplerDesc, &_sampler_state);
RETURN_ON_FAIL(hr);
return hr;
}
HRESULT CDxRender::Resize(const UINT32& w, const UINT32& h)
{
_render_target_view = nullptr;
_back_texture2d = nullptr;
_back_dxgi_surface = nullptr;
_back_d2d1_bitmap = nullptr;
_back_render_target = nullptr;
HRESULT hr = _swap_chain1->ResizeBuffers(2, w, h, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
RETURN_ON_FAIL(hr);
hr = _swap_chain1->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&_back_texture2d);
RETURN_ON_FAIL(hr);
hr = _d3d11_device->CreateRenderTargetView(_back_texture2d, NULL, &_render_target_view);
RETURN_ON_FAIL(hr);
_deferred_context->OMSetRenderTargets(1, &_render_target_view.p, NULL);
hr = _back_texture2d->QueryInterface(IID_PPV_ARGS(&_back_dxgi_surface));
RETURN_ON_FAIL(hr);
#if 1
UINT dpi = GetDpiForWindow(m_hWnd);
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), static_cast<float>(dpi), static_cast<float>(dpi));
hr = _d2d_factory->CreateDxgiSurfaceRenderTarget(_back_dxgi_surface, &props, &_back_render_target);
RETURN_ON_FAIL(hr);
float dpi_x = 0.f;
float dpi_y = 0.f;
_back_render_target->GetDpi(&dpi_x, &dpi_y);
D2D1_SIZE_U src_sizeU = _back_render_target->GetPixelSize();
D2D1_BITMAP_PROPERTIES prop = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), dpi_x, dpi_y);
hr = _back_render_target->CreateBitmap(src_sizeU, prop, &_back_d2d1_bitmap);
RETURN_ON_FAIL(hr);
#endif
return hr;
}
void CDxRender::PreRender(const UINT32& w, const UINT32& h)
{
unsigned __int32 stride = sizeof(DefVertBuffer);
unsigned __int32 offset = 0;
_deferred_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
_deferred_context->IASetIndexBuffer(_index_buffer, DXGI_FORMAT_R32_UINT, 0);
_deferred_context->IASetVertexBuffers(0, 1, &_vert_buffer.p, &stride, &offset);
_deferred_context->PSSetShader(_pixel_shader, 0, 0);
_deferred_context->VSSetShader(_vertex_shader, 0, 0);
_deferred_context->IASetInputLayout(_input_layout);
_deferred_context->PSSetSamplers(0, 1, &_sampler_state.p);
_deferred_context->OMSetRenderTargets(1, &_render_target_view.p, nullptr);
D3D11_VIEWPORT viewPort;
unsigned int viewPort_index = 1ui32;
_deferred_context->RSGetViewports(&viewPort_index, &viewPort);
viewPort.Width = static_cast<float>(w);
viewPort.Height = static_cast<float>(h);
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
_deferred_context->RSSetViewports(1, &viewPort);
}
void CDxRender::DrawScene()
{
RECT client_rect;
GetClientRect(&client_rect);
PreRender(client_rect.right - client_rect.left, client_rect.bottom - client_rect.top);
FLOAT bgArray[][4] =
{
{ 1.f, 0.f, 0.f, 1.0f },
{ 0.f, 1.f, 0.f, 1.0f },
{ 0.f, 0.f, 1.f, 1.0f },
{ 1.f, 0.f, 1.f, 1.0f },
{ 1.f, 1.f, 0.f, 1.0f },
{ 0.f, 1.f, 1.f, 1.0f },
{ 1.f, 1.f, 1.f, 1.0f },
{ 0.f, 0.f, 0.f, 1.0f },
};
INT64 counter = (_capture_counter / (5 * fps)) % ARRAYSIZE(bgArray);
FLOAT* bgColor = bgArray[counter];
#if 1
CComPtr<ID2D1SolidColorBrush> whiteBrush;
_back_render_target->CreateSolidColorBrush(D2D1::ColorF(1.f, 1.f, 0.f, 1.f), &whiteBrush);
// draw the text
D2D1_SIZE_F border = _back_render_target->GetSize();
float _offset_x = (rand() % 20 - 10) / 10.f;
float _offset_y = (rand() % 20 - 10) / 10.f;
_back_render_target->BeginDraw();
_back_render_target->Clear(D2D1::ColorF(bgColor[0], bgColor[1], bgColor[2], bgColor[3]));
_back_render_target->FillRectangle(D2D1::RectF(200 - 50 * _offset_y, 200 - 50 * _offset_x, 800 + 50 * (_offset_x + _offset_y) / 2, 600 - 50 * (_offset_x + _offset_y) / 2), whiteBrush);
_back_render_target->DrawRectangle(D2D1::RectF(100 + 50 * _offset_x, 100 + 50 * _offset_y, border.width - 100 - 50 * (_offset_x + _offset_y) / 2, border.height - 100 + 50 * (_offset_x + _offset_y) / 2), whiteBrush, 10.f);
hr = _back_render_target->EndDraw();///<------------will debug breakpoint here
#endif
ExecuteCommandList(_deferred_context);
//Present the backbuffer to the screen
_swap_chain1->Present(0, 0);
}
4 , PixelShader.hlsl:
struct PS_Input
{
float4 pos:SV_POSITION;
float4 color:COLOR;
float2 texCoord:TEXCOORD;
};
Texture2D objTexture :register(t0);
SamplerState objSamplerState;
float4 main(PS_Input input) : SV_TARGET
{
/*float4 retColor = 0;
retColor = objTexture.Sample(objSamplerState, input.texCoord) * input.color;
clip(retColor.a - 0.3);
return retColor;*/
return input.color;
}
5 , VertexShader.hlsl:
struct VS_Input
{
float4 pos:POSITION;
float4 color:COLOR;
float2 texCoord:TEXCOORD;
};
struct VS_Output
{
float4 pos:SV_POSITION;
float4 color:COLOR;
float2 texCoord:TEXCOORD;
};
VS_Output main(VS_Input input)
{
VS_Output output;
output.pos = input.pos;/*mul(input.pos, WVP);*/
output.color = input.color;
output.texCoord = input.texCoord;
return output;
}