directx-11 - 如何支持(在win7上)GDI、D3D11互操作?
问题描述
我创建了一个D3D11设备,可以流畅地进行渲染图片等操作,但是为了也支持GDI,我尝试了几种方法:
- 通过swapchain -> GetBuffer(ID3D11Texture2D) -> CreateDxgiSurfaceRenderTarget -> ID2D1GdiInteropRenderTarget -> GetDC,最终得到DC。在我的Win10上运行正常,但是在Win7上运行GetDC时报异常:_com_error。
- 通过swapchain -> GetBuffer(IDXGISurface1) -> GetDC,同1。
我怀疑在Win7上GetBuffer得到的ID3D11Texture2D/IDXGISurface1会对GDI的使用有一定的限制,所以我改成自己动态新建一个ID3D11Texture2D,现在单独使用DC/单独使用D3D11绘图界面就可以了,但是如果我互操作,会发现gdi操作是在自定义创建的ID3D11Texture2D上绘制的,而不是swapchain的back_buffer:
_d3d->Clear();
_d3d->DrawImage();
HDC hdc = _d3d->GetDC();
DrawRectangleByGDI(hdc);
_d3d->ReleaseDC();
_d3d->Present();
那么怎么做:无论是D3D还是DC方法绘制,都在同一个ID3D11Texture2D上?这样,我的 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;
}
解决方案
我认为 Windows 7 不支持您尝试执行的操作。这里有一些替代方案。
从 GDI 切换到其他可以使用 D3D11 渲染 2D 图形的东西。Direct2D 是这里最直接的选择。如果你想要除了矩形之外的文本,还有 DirectWrite。
如果您的 2D 内容是静态的或很少更改,您可以使用 GDI+ 渲染到内存中的 RGBA 设备上下文中,使用该数据创建 Direct3D11 纹理,并使用该纹理渲染一个全屏三角形。
您可以在 Direct3D 11 渲染窗口之上覆盖另一个 Win32 窗口,然后使用 GDI 渲染到该窗口中。顶部的 GDI 窗口必须具有 WS_EX_LAYERED 扩展样式,并且您必须使用 UpdateLayeredWindow API 对其进行更新。但是,这种方法是最复杂和最不可靠的。
推荐阅读
- html - CSS - 对齐内容不影响弹性项目
- c# - 拿一个 Console.ReadLine(); 输入并将其放入列表中
? - google-sheets - 将实时数据从 scada wincc 导出到 google sheet
- node.js - 找不到Nodejs模块
- swift - 我的 Fetched Results Controller 没有在旧条目中对新条目进行排序
- javascript - 如何使用 TypeScript 为响应中的对象编写状态类型?
- r - 映射列表并获取 r 中的 colmeans 和 rowmeans
- android - 如何在另一个 recyclerview 中为 recyclerview 设置第二个布局管理器?
- javascript - how can i add a value in an array of object if the date is same in NodeJS?
- swift - 使用惰性变量与初始化 - Swift