I created a D3D11 device and can perform operations such as rendering pictures smoothly, but in order to also support GDI, I tried several methods:
- Through swapchain -> GetBuffer(ID3D11Texture2D) -> CreateDxgiSurfaceRenderTarget -> ID2D1GdiInteropRenderTarget -> GetDC, finally get the DC. It runs normally on my Win10, but an exception report when running GetDC on Win7: _com_error.
- Via swapchain -> GetBuffer(IDXGISurface1) -> GetDC, same as 1.
I suspect that the ID3D11Texture2D/IDXGISurface1 obtained by GetBuffer on Win7 will have some restrictions on the use of GDI, so I changed to dynamically create a new ID3D11Texture2D by myself, and now use DC alone/D3D11 drawing interface alone It works fine, but if I interoperate, I will find that gdi opertaion is drawn on the custom-created ID3D11Texture2D instead of the back_buffer of swapchain:
_d3d->Clear();
_d3d->DrawImage();
HDC hdc = _d3d->GetDC();
DrawRectangleByGDI(hdc);
_d3d->ReleaseDC();
_d3d->Present();
So how to do it: Whether the D3D or DC methods is drawn, they are all on the same ID3D11Texture2D? This way, it is also convenient for my CopyResource.
HRESULT CGraphRender::Resize(const UINT32& width, const UINT32& height)
{
_back_texture2d = nullptr;
_back_rendertarget_view = nullptr;
_dc_texture2d = nullptr;
_dc_render_target = nullptr;
float dpi = GetDpiFromD2DFactory(_d2d_factory);
//Backbuffer
HRESULT hr = _swap_chain->ResizeBuffers(2, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, _is_gdi_compatible ? DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE : 0);
RETURN_ON_FAIL(hr);
hr = _swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&_back_texture2d);
RETURN_ON_FAIL(hr);
hr = CreateD3D11Texture2D(_d3d_device, width, height, &_dc_texture2d);
RETURN_ON_FAIL(hr);
D3D11_RENDER_TARGET_VIEW_DESC rtv;
rtv.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv.Texture2D.MipSlice = 0;
hr = _d3d_device->CreateRenderTargetView(_back_texture2d, &rtv, &_back_rendertarget_view);
RETURN_ON_FAIL(hr);
...
}
HRESULT CGraphRender::Clear(float color[])
{
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11RenderTargetView* ref_renderTargetView = _back_rendertarget_view;
immediate_context->OMSetRenderTargets(1, &ref_renderTargetView, nullptr);
immediate_context->ClearRenderTargetView(_back_rendertarget_view, color);
return S_OK;
}
HDC CGraphRender::GetDC()
{
if (_is_gdi_compatible)
{
CComPtr<IDXGISurface1> gdi_surface;
HRESULT hr = _dc_texture2d->QueryInterface(__uuidof(IDXGISurface1), (void**)&gdi_surface);
if (SUCCEEDED(hr))
{
HDC hdc = nullptr;
hr = gdi_surface->GetDC(TRUE, &hdc);
if (SUCCEEDED(hr))
{
return hdc;
}
}
}
return nullptr;
}
HRESULT CGraphRender::CopyTexture(ID3D11Texture2D* dst_texture, ID3D11Texture2D* src_texture, POINT* dst_topleft/* = nullptr*/, POINT* src_topleft/* = nullptr*/)
{
if (!dst_texture && !src_texture)
{
return E_INVALIDARG;
}
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11Texture2D* dst_texture_real = dst_texture ? dst_texture : _dc_texture2d;
POINT dst_topleft_real = dst_topleft ? (*dst_topleft) : POINT{ 0, 0 };
ID3D11Texture2D* src_texture_real = src_texture ? src_texture : _dc_texture2d;
POINT src_topleft_real = src_topleft ? (*src_topleft) : POINT{ 0, 0 };
D3D11_TEXTURE2D_DESC src_desc = { 0 };
src_texture_real->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC dst_desc = { 0 };
dst_texture_real->GetDesc(&dst_desc);
if (!dst_topleft_real.x && !src_topleft_real.x && !dst_topleft_real.y && !src_topleft_real.y && dst_desc.Width == src_desc.Width && dst_desc.Height == src_desc.Height)
{
immediate_context->CopyResource(dst_texture_real, src_texture_real);
}
else
{
D3D11_BOX src_box;
src_box.left = min((UINT)src_topleft_real.x, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.top = min((UINT)src_topleft_real.y, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.right = min((UINT)src_box.left + src_desc.Width, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.bottom = min((UINT)src_box.top + src_desc.Height, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.front = 0;
src_box.back = 1;
ATLASSERT(src_box.left < src_box.right);
ATLASSERT(src_box.top < src_box.bottom);
immediate_context->CopySubresourceRegion(dst_texture_real, 0, dst_topleft_real.x, dst_topleft_real.y, 0, src_texture_real, 0, &src_box);
}
return S_OK;
}
I don’t think Windows 7 supports what you’re trying to do. Here’s some alternatives.
Switch from GDI to something else that can render 2D graphics with D3D11. Direct2D is the most straightforward choice here. And DirectWrite if you want text in addition to rectangles.
If your 2D content is static or only changes rarely, you can use GDI+ to render into in-memory RGBA device context, create Direct3D11 texture with that data, and render a full-screen triangle with that texture.
You can overlay another Win32 window on top of your Direct3D 11 rendering one, and use GDI to render into that one. The GDI window on top must have WS_EX_LAYERED expended style, and you must update it with UpdateLayeredWindow API. This method is the most complicated and least reliable, though.