D3D11:如何将 GDI 文本绘制到 GXDI 表面? (无 D2D)

发布于 2024-11-07 11:33:23 字数 1269 浏览 5 评论 0原文

我需要一些帮助来使用 GDI 和 D3D11 将文本绘制到纹理。我尝试使用 D2D/DirectWrite,但它仅支持 D3D10,而不支持我需要的 D3D11。到目前为止我尝试的一切都失败了...... 现在我想使用GDI方法来写入纹理。 所以我用这个参数创建了一个纹理:

Usage = D3D11_USAGE_DEFAULT;
Format = DXGI_FORMAT_B8G8R8A8_UNORM;
BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
CPUAccessFlags = 0;
MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE

然后我从这个纹理创建了一个普通的RenderTargetView,正如微软在这里所说的:http://msdn.microsoft.com/en-us/library/ff476203%28v=vs.85%29.aspx

下一步:获取 DXGI 接口:

m_pTexFSText->QueryInterface(__uuidof(IDXGISurface1), (void **)(&m_pDXGISurface));

在渲染功能上我就是这样做的:

m_pDeviceContext->OMSetRenderTargets(1,&m_pTextRenderTarget,NULL);

HDC hDc = NULL;
if(FAILED(m_pDXGISurface->GetDC(TRUE,&hDc)))
    return E_FAIL;

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
bool hmm = TextOutA(hDc, 10, 10, "LALALA!", 7);

if(FAILED(m_pDXGISurface->ReleaseDC(NULL)))
    return E_FAIL;

问题是,在 GDI 绘图之后纹理仍然是空的(也用 PIX 进行了测试)。 一切正常,没有错误消息。

我希望任何人都可以解释它是如何工作的。

谢谢,Stefan

编辑:也尝试使用 GetDC(FALSE,&hDc) (根据文档):相同的结果 ->没有什么。

I need some help with drawing a text to a texture with GDI and D3D11. I tried using D2D/DirectWrite, but it supports just D3D10 and not D3D11 as I need. Everything I tried failed so far...
Now I want to use GDI methodes to write in the texture.
So I created a texture with this params:

Usage = D3D11_USAGE_DEFAULT;
Format = DXGI_FORMAT_B8G8R8A8_UNORM;
BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
CPUAccessFlags = 0;
MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE

Then I created a normal RenderTargetView from this texture as Microsoft sais here: http://msdn.microsoft.com/en-us/library/ff476203%28v=vs.85%29.aspx

Next Step: Get The DXGI Interface:

m_pTexFSText->QueryInterface(__uuidof(IDXGISurface1), (void **)(&m_pDXGISurface));

On the Render function I do just this:

m_pDeviceContext->OMSetRenderTargets(1,&m_pTextRenderTarget,NULL);

HDC hDc = NULL;
if(FAILED(m_pDXGISurface->GetDC(TRUE,&hDc)))
    return E_FAIL;

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
bool hmm = TextOutA(hDc, 10, 10, "LALALA!", 7);

if(FAILED(m_pDXGISurface->ReleaseDC(NULL)))
    return E_FAIL;

The problem is, that the texture is still empty after that GDI drawing (Also tested with PIX).
Everything works and there are no error messages.

I hope that anybody can explain how it works.

Thanks, Stefan

EDIT: Tried it also with GetDC(FALSE,&hDc) (according to the documentation): same results -> nothing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你与清晨阳光 2024-11-14 11:33:23

实际上,上周我经常与这个问题作斗争 - 但我已经全部解决了!以下是您应该了解/执行的事项列表,以使其全部正常工作:

使用此方法时请记住以下几点:

•您必须使用表面的 D3D11_RESOURCE_MISC_GDI_COMPATIBLE 标志或交换链的 DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE 标志来创建表面,否则此方法将失败。

•在发出任何新的 Direct3D 命令之前,您必须释放设备并调用 IDXGISurface1::ReleaseDC 方法。

•如果已通过此方法创建了未完成的 DC,则此方法将失败。

•表面或交换链的格式必须为 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB 或 DXGI_FORMAT_B8G8R8A8_UNORM。

•在 GetDC 上,Direct3D 管道的输出合并中的渲染目标与表面解除绑定。在 GDI 渲染之后进行 Direct3D 渲染之前,您必须在设备上调用 ID3D11DeviceContext::OMSetRenderTargets 方法。

•在调整缓冲区大小之前,您必须释放所有未完成的 DC。

  • 如果您要在后台缓冲区中使用它,请记住在调用 ReleaseDC 后重新绑定渲染目标。在调用 GetDC 之前无需手动取消绑定 RT,因为此方法会为您完成此操作。

  • 您不能在 GetDC() 和 ReleaseDC() 调用之间使用任何 Direct3D 绘图,因为表面被 DXGI 针对 GDI 专门锁定。但是,您可以混合 GDI 和 D3D 渲染,前提是每次需要使用 GDI 时调用 GetDC()/ReleaseDC(),然后再转向 D3D。

  • 最后一点可能听起来很简单,但您会惊讶地发现有多少开发人员陷入了这个问题 - 当您在后台缓冲区上使用 GDI 进行绘制时,请记住这是后台缓冲区,而不是一个帧缓冲区,所以为了真正看到你绘制的内容,你必须将 RT 重新绑定到 OM 并调用 swapChain->Present() 方法,这样后备缓冲区将变成帧缓冲区,其内容将显示在屏幕上.

I actually fought this problem a lot during last week - but I've got it all working! Here is a list of things you should know/do to make it all work:

Keep the following in mind when using this method:

•You must create the surface by using the D3D11_RESOURCE_MISC_GDI_COMPATIBLE flag for a surface or by using the DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE flag for swap chains, otherwise this method fails.

•You must release the device and call the IDXGISurface1::ReleaseDC method before you issue any new Direct3D commands.

•This method fails if an outstanding DC has already been created by this method.

•The format for the surface or swap chain must be DXGI_FORMAT_B8G8R8A8_UNORM_SRGB or DXGI_FORMAT_B8G8R8A8_UNORM.

•On GetDC, the render target in the output merger of the Direct3D pipeline is unbound from the surface. You must call the ID3D11DeviceContext::OMSetRenderTargets method on the device prior to Direct3D rendering after GDI rendering.

•Prior to resizing buffers you must release all outstanding DCs.

  • If you're going to use it in the back buffer, remember to re-bind render target after you've called ReleaseDC. It is not neccessary to manually unbind RT before calling GetDC as this method does that for you.

  • You can not use any Direct3D drawing between GetDC() and ReleaseDC() calls as the surface is excusively locked out by DXGI for GDI. However you can mix GDI and D3D rendering provided that you call GetDC()/ReleaseDC() every time you need to use GDI, before moving on to D3D.

  • This last bit may sounds easy, but you'd be surprised how many developers fall into this issue - when you draw with GDI on the back buffer, remember that this is the back buffer, not a framebuffer, so in order to actually see what you've drawn, you have to re-bind RT to OM and call swapChain->Present() method so the backbuffer will become a framebuffer and its contents will be displayed on the screen.

痴者 2024-11-14 11:33:23

也许你做的一切都很好,只是文本绘制没有达到你的预期?

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
bool hmm = TextOutA(hDc, 10, 10, "LALALA!", 7);

我不明白您如何期望 TextOutA 会猜测 bla 应该用作文本颜色。据我所知,新创建/获得的 DC 中使用的默认文本颜色是黑色。不确定背景填充模式,但如果默认情况下是透明的 - 这充分解释了为什么没有绘制任何内容。

我会将您的代码更改为以下内容:

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
VERIFY(SetTextColor(hDc, bla) != CLR_INVALID);

CREct rc(0, 0, 30, 20); // put relevant coordinates
VERIFY(ExtTextOut(hDc, rc.left, rc.top, ETO_CLIPPED, &rc, "LALALA!", 7));

Maybe you're doing everything fine, it's just the text drawing doesn't do what you expect?

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
bool hmm = TextOutA(hDc, 10, 10, "LALALA!", 7);

I don't understand from this how do you expect that TextOutA will guess that bla should be used as the text color. AFAIK the default text color used in the newly created/obtained DC is black. Not sure about the background fill mode, but if it's TRANSPARENT by default - this fully explains why nothing is drawing.

I'd change your code to the following:

COLORREF bla = SetPixel(hDc,1,1,RGB(255,255,255));
VERIFY(SetTextColor(hDc, bla) != CLR_INVALID);

CREct rc(0, 0, 30, 20); // put relevant coordinates
VERIFY(ExtTextOut(hDc, rc.left, rc.top, ETO_CLIPPED, &rc, "LALALA!", 7));
黯淡〆 2024-11-14 11:33:23

我将在后台缓冲区中使用它。我不确定它是否正确完成。我看不到图。显示的是黑色的啊

HDC GetSurfaceDC()
{
    m_pSurface1 = nullptr;
    HDC hdc{};

    //Setup the swapchain surface
    IF_FAILED_THROW_HR(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_pSurface1)));

    // Obtain the back buffer for this window which will be the final 3D render target.
    ID3D11Texture2DPtr backBuffer;
    IF_FAILED_THROW_HR(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)));

    // Create a descriptor for the RenderTargetView.
    CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DXGI_FORMAT_B8G8R8A8_UNORM, 0, 0, 1);

    ID3D11RenderTargetViewPtr renderTargetView;

    // Create a view interface on the render target to use on bind for mono or left eye view.
    IF_FAILED_THROW_HR(m_device->CreateRenderTargetView(backBuffer, &renderTargetViewDesc, &renderTargetView));

    m_context->OMSetRenderTargets(1, &renderTargetView.GetInterfacePtr(), nullptr);

    IF_FAILED_THROW_HR(m_pSurface1->GetDC(FALSE, &hdc));
    return hdc;
}

void ReleaseSurfaceDC()
{
     if (m_pSurface1 == nullptr)
        return;
     //When finish drawing release the DC
     m_pSurface1->ReleaseDC(nullptr);

     m_context->OMSetRenderTargets(1, &m_renderTargetView.GetInterfacePtr(), m_depthStencilView);
}

我使用了交换链描述:

    DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;

I am going to use it in the back buffer. I am not sure if it's done correctly. I can't see the drawing. It's showing black.

HDC GetSurfaceDC()
{
    m_pSurface1 = nullptr;
    HDC hdc{};

    //Setup the swapchain surface
    IF_FAILED_THROW_HR(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_pSurface1)));

    // Obtain the back buffer for this window which will be the final 3D render target.
    ID3D11Texture2DPtr backBuffer;
    IF_FAILED_THROW_HR(m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)));

    // Create a descriptor for the RenderTargetView.
    CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DXGI_FORMAT_B8G8R8A8_UNORM, 0, 0, 1);

    ID3D11RenderTargetViewPtr renderTargetView;

    // Create a view interface on the render target to use on bind for mono or left eye view.
    IF_FAILED_THROW_HR(m_device->CreateRenderTargetView(backBuffer, &renderTargetViewDesc, &renderTargetView));

    m_context->OMSetRenderTargets(1, &renderTargetView.GetInterfacePtr(), nullptr);

    IF_FAILED_THROW_HR(m_pSurface1->GetDC(FALSE, &hdc));
    return hdc;
}

void ReleaseSurfaceDC()
{
     if (m_pSurface1 == nullptr)
        return;
     //When finish drawing release the DC
     m_pSurface1->ReleaseDC(nullptr);

     m_context->OMSetRenderTargets(1, &m_renderTargetView.GetInterfacePtr(), m_depthStencilView);
}

I have used swap chain desc:

    DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文