8

在使用 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 测试过)。一切正常,没有错误消息。

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

谢谢,斯特凡

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

4

3 回答 3

7

实际上,我在上周经常解决这个问题 - 但我已经完成了所有工作!以下是您应该知道/做的事情的清单,以使其一切正常:

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

• 您必须使用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 for GDI 专门锁定。但是,您可以混合使用 GDI 和 D3D 渲染,前提是您每次需要使用 GDI 时都调用 GetDC()/ReleaseDC(),然后再转到 D3D。

  • 最后一点可能听起来很简单,但你会惊讶于有多少开发人员陷入了这个问题——当你在后台缓冲区上使用 GDI 绘图时,请记住这是后台缓冲区,而不是帧缓冲区,所以为了真正看到什么你已经画好了,你必须重新绑定RT到OM并调用swapChain->Present()方法,这样backbuffer就会变成一个framebuffer,它的内容就会显示在屏幕上。

于 2012-01-09T20:47:30.563 回答
3

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

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

我不明白你怎么TextOutA会猜到bla应该用作文本颜色。AFAIK 新创建/获得的 DC 中使用的默认文本颜色为黑色。不确定背景填充模式,但如果它是TRANSPARENT默认的 - 这完全解释了为什么什么都没有绘制。

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

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));
于 2011-05-16T09:19:25.317 回答
0

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

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);
}

我使用了交换链 desc:

    DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
于 2019-01-28T06:49:34.247 回答