Get GDI DC from ID3D11Texture2D for drawing

2

I have an implementation in directx9 where I have taken GDI DC to render drawing. But the similar code in directx11 does not get GDI DC instead throws invalid call exception.

Implementation in directx9:

IF_DX9ERR_THROW_HR(m_spIDevice->CreateTexture(UINT(cSizeOverlay.cx), UINT(cSizeOverlay.cy), 1, D3DUSAGE_DYNAMIC,  D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_spIOverlay, nullptr));
m_spIOverlaySurface = nullptr;
IF_DX9ERR_THROW_HR(m_spIOverlay->GetSurfaceLevel(0, &m_spIOverlaySurface));
D3DSURFACE_DESC descOverlay;
::ZeroMemory(&descOverlay, sizeof(descOverlay));
IF_DX9ERR_THROW_HR(m_spIOverlaySurface->GetDesc(&descOverlay));
// fill the texture with the color key
CRect cRect(0, 0, descOverlay.Width, descOverlay.Height);
HDC hDC = nullptr;
IF_DX9ERR_THROW_HR(m_spIOverlaySurface->GetDC(&hDC));
::SetBkColor(hDC, colKey);
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, cRect, nullptr, 0, nullptr);
IF_DX9ERR_THROW_HR(m_spIOverlaySurface->ReleaseDC(hDC));

Implementation in directx11:

D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Width = gsl::narrow_cast<UINT>(width);
desc.Height = gsl::narrow_cast<UINT>(height);
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;

ID3D11DevicePtr device = renderer->Device();
ID3D11Texture2DPtr  texture2D;
IF_FAILED_THROW_HR(device->CreateTexture2D(&desc, nullptr, &texture2D));    
// get texture surface
IDXGISurface1Ptr dxgiSurface1 = tex2D;

IF_FAILED_THROW_HR(dxgiSurface1->GetDC(FALSE, &m_overlayDC));
//Draw on the DC using GDI
if (!m_overlayDC) // we have lost the device
    THROW_PE(IDS_ERR_NO_VIDEO_HARDWARE);
::SetBkColor(m_overlayDC, m_effectConstants.m_keyColor);
::ExtTextOut(m_overlayDC, 0, 0, ETO_OPAQUE, overlayRect, nullptr, 0, nullptr);
//When finish drawing release the DC
dxgiSurface1->ReleaseDC(nullptr);

m_overlayDC = nullptr;

Edit: I have changed the D3D11_TEXTURE2D_DESC like below:

    CD3D11_TEXTURE2D_DESC texDesc(DXGI_FORMAT_B8G8R8X8_UNORM
    , gsl::narrow_cast<UINT>(targetSize.width), gsl::narrow_cast<UINT>(targetSize.height), 1U, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);

ID3D11DevicePtr device = renderer->Device();
ID3D11Texture2DPtr  texture2D;
IF_FAILED_THROW_HR(device->CreateTexture2D(&texDesc, nullptr, &texture2D));

// get texture surface
IDXGISurface1Ptr dxgiSurface1 = texture2D;

IF_FAILED_THROW_HR(dxgiSurface1->GetDC(FALSE, &m_overlayDC));
//Draw on the DC using GDI
if (!m_overlayDC) // we have lost the device
    THROW_PE(IDS_ERR_NO_VIDEO_HARDWARE);
::SetBkColor(m_overlayDC, m_effectConstants.m_keyColor);
::ExtTextOut(m_overlayDC, 0, 0, ETO_OPAQUE, overlayRect, nullptr, 0, nullptr);
//When finish drawing release the DC
dxgiSurface1->ReleaseDC(nullptr);

m_overlayDC = nullptr;

Now the exception thrown from GetDC(): The application made a call that is invalid. Either the parameters of the call or the state of some object was incorrect. Enable the D3D debug layer in order to see details via debug messages. HResult: 0x887A0001, Facility: 2170, Code: 1

c++11
gdi
directx-11
directx-9
texture2d
asked on Stack Overflow Jan 28, 2019 by Tajuddin Khandaker • edited Jan 30, 2019 by Tajuddin Khandaker

1 Answer

1

The combination of format, usage, and bind flags you have picked are not compatible with D3D11_RESOURCE_MISC_GDI_COMPATIBLE.

If you enable Direct3D Debug Device, you'd have gotten debug output to inform you of this limitation. The Direct3D Debug Device is the ideal way to figure out why you are getting E_INVALIDARG.

D3D11 ERROR: ID3D11Device::CreateTexture2D: D3D11_RESOURCE_MISC_GDI_COMPATIBLE requires that the D3D11_BIND_RENDER_TARGET flag be set. [ STATE_CREATION ERROR #103: CREATETEXTURE2D_INVALIDMISCFLAGS]

Then after fixing that, you get:

D3D11 ERROR: ID3D11Device::CreateTexture2D: D3D11_RESOURCE_MISC_GDI_COMPATIBLE requires D3D11_USAGE_DEFAULT. [ STATE_CREATION ERROR #103: CREATETEXTURE2D_INVALIDMISCFLAGS]``.

And finally:

D3D11 ERROR: ID3D11Device::CreateTexture2D: D3D11_RESOURCE_MISC_GDI_COMPATIBLE requires a B8G8R8A8 format. [ STATE_CREATION ERROR #103: CREATETEXTURE2D_INVALIDMISCFLAGS]

So taking this all together, this works:

D3D11_TEXTURE2D_DESC desc = {};
desc.Width = ...
desc.Height = ...
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;

Microsoft::WRL::ComPtr<ID3D11Texture2D> texture2D;
DX::ThrowIfFailed(m_d3dDevice->CreateTexture2D(&desc, nullptr, &texture2D));

The limitations are all spelled out on Microsoft Docs

answered on Stack Overflow Jan 30, 2019 by Chuck Walbourn

User contributions licensed under CC BY-SA 3.0