• FEATURED

View more

View more

View more

\$59

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

## D2D + D3D11 help me to make them work together

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

20 replies to this topic

### #1BlackJoker  Members

Posted 01 March 2013 - 06:38 AM

Hello to all!

I have a problem with connecting D2D to D3D11. I read a lot of forum articles on that theme, but this interop a little bit hard to understand and more harder to use on practice. I tried to implement it as was saying in this article http://www.braynzarsoft.net/index.php?p=D3D11FONT#still but problem in that in the sample all the code is in 1 file and there is no OOP at all, and I make my engine from the rasterteck framework.

I think during implementation of interop D2D and D3D11 I missed something, but I cant find the problem because program work without errors, but just no text on the screen.

I uploaded my project here, so if you wish to help me, you can look into code and say where i have a mistake because I am completely confused with this problem.

Could someone build up this project and find out why text is not rendered?

I am trying to find a solution already a week, but unsuccessfully.

P.S. I chose to implement D2D + D3D11 because the way to cut texture into pieces seems no so good way to make text output for me, besides it hard to make localization in that way.

### #2/Jeff/  Members

Posted 01 March 2013 - 06:12 PM

I don't have a good resource available to explain this, but I just thought I'd let you know that Microsoft released a platform update on 2/26/2013 that makes a lot of the things in that article unnecessary. It's now possible to use D3D11 and D2D together directly, without having to create a D3D10.1 device and worry about synchronizing the resources.

If you've installed the update, you should be able to just create a D3D11 texture, get an IDXGISurface1 pointer from it, and then pass that to CreateDxgiSurfaceRenderTarget to create a D2D render target.

Edited by jrh2365, 01 March 2013 - 06:22 PM.

### #3BlackJoker  Members

Posted 02 March 2013 - 02:55 AM

Edited by BlackJoker, 02 March 2013 - 02:55 AM.

### #4Alessio1989  Members

Posted 02 March 2013 - 07:21 AM

You can use  Direct2D 1.1 since it is fully available for Windows 7 too. http://msdn.microsoft.com/en-us/library/windows/desktop/jj863687.aspx

Edited by Alessio1989, 02 March 2013 - 07:22 AM.

"Recursion is the first step towards madness." - "Skeggǫld, Skálmǫld, Skildir ro Klofnir!"
Direct3D 12 quick reference: https://github.com/alessiot89/D3D12QuickRef/

### #5/Jeff/  Members

Posted 02 March 2013 - 08:17 AM

Actually, if you are on Windows 8 it was possible before the update. The update (http://support.microsoft.com/kb/2670838) was only for allowing it to work on Windows 7 as well.

Here is a sample for D3D-D2D interop on Windows 8. I didn't get a chance to look at it, but it might be useful.

http://code.msdn.microsoft.com/windowsapps/Direct2D-Direct3D-Interop-ee641e46

Also, here's a quick example I threw together, using D2D to draw text to the backbuffer. It should also be possible to create a texture in D3D11, and then write to it with D2D. (I think you would use QueryInterface to get the IDXGISurface1 pointer from the texture, and then pass that to CreateDxgiSurfaceRenderTarget, but I'm not sure)

#include <Windows.h>
#include <d3d11.h>
#include <d2d1_1.h>
#include <dwrite_1.h>

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dwrite.lib")

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_CLOSE)
{
PostQuitMessage(0);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// create the window

WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hInstance;
wcex.hbrBackground = NULL;
wcex.lpszClassName = "Vector";
ATOM a = RegisterClassEx(&wcex);

RECT r = {0, 0, 800, 600};

HWND hWnd = CreateWindow(
(LPCSTR)a,
"Vector",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
r.right - r.left,
r.bottom - r.top,
NULL,
NULL,
hInstance,
NULL);

// create the D3D device and swap chain

D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;

DXGI_SWAP_CHAIN_DESC swapChainDesc = { };
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = 800;
swapChainDesc.BufferDesc.Height = 600;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hWnd;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Windowed = true;

IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *context;

HRESULT hr = D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_BGRA_SUPPORT,
&level,
1,
D3D11_SDK_VERSION,
&swapChainDesc,
&swapChain,
&device,
NULL,
&context);

// set up the D3D render target view to the back buffer

ID3D11Texture2D *backBuffer;
ID3D11RenderTargetView *backBufferView;
swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
device->CreateRenderTargetView(backBuffer, NULL, &backBufferView);
context->OMSetRenderTargets(1, &backBufferView, NULL);

// create the D2D factory

ID2D1Factory *factory;
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;

// set up the D2D render target using the back buffer

IDXGISurface *dxgiBackbuffer;
swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackbuffer));
ID2D1RenderTarget *d2dRenderTarget;
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
factory->CreateDxgiSurfaceRenderTarget(dxgiBackbuffer, props, &d2dRenderTarget);
dxgiBackbuffer->Release();

// create the DWrite factory

IDWriteFactory1 *writeFactory;
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(writeFactory), (IUnknown**)(&writeFactory));

// create the DRwite text format

IDWriteTextFormat *textFormat;
writeFactory->CreateTextFormat(
L"Arial",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
50,
L"",
&textFormat);

// create a brush

ID2D1SolidColorBrush *whiteBrush;
d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &whiteBrush);

// draw the text

d2dRenderTarget->BeginDraw();
const WCHAR *text = L"Hello World";
d2dRenderTarget->DrawTextA(text, wcslen(text), textFormat, D2D1::RectF(0, 0, 800, 600), whiteBrush);
d2dRenderTarget->EndDraw();

ShowWindow(hWnd, true);

MSG msg = {0};
while (WM_QUIT != msg.message)
{
if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
swapChain->Present(0, 0);
}
}
}


### #6BlackJoker  Members

Posted 02 March 2013 - 08:52 AM

I didnt know that D2D1_1 I can use with D3D11 on Win8. Thanks for that.

hm, it seems that i cannot build that MS sample because my VS 2012 says that this project is incompatible with my version of VS. I have Ultimate version.

Does someone know how to build that project?

### #7BlackJoker  Members

Posted 02 March 2013 - 09:28 AM

And another one thing - now I must use Windows 8 SDK to use new D2D, but here is no D3DX.h, so I must find new analogs for old functions such as D3DXMatrixPerspectiveFovLH and D3DXCreateTextureFromFile

Does someone now which functions I can replace these?

By the way. I have tested you code and it work great after few small corrections regarding CreateWindow function. Thanks a lot for this, but I still dont know whixh functions to use instead of D3DX functions. Could you please help me with that question?

Edited by BlackJoker, 02 March 2013 - 10:03 AM.

### #8BlackJoker  Members

Posted 02 March 2013 - 02:15 PM

And another one question: how to get last position of drawn symbol in D2D? For example I want to draw text after previous, but for thi I need to now where the rivious text ended on the screen. Could I get this information somehow?

### #9Alessio1989  Members

Posted 02 March 2013 - 05:59 PM

And another one thing - now I must use Windows 8 SDK to use new D2D, but here is no D3DX.h, so I must find new analogs for old functions such as D3DXMatrixPerspectiveFovLH and D3DXCreateTextureFromFile

Does someone now which functions I can replace these?

By the way. I have tested you code and it work great after few small corrections regarding CreateWindow function. Thanks a lot for this, but I still dont know whixh functions to use instead of D3DX functions. Could you please help me with that question?

Since D3DX is retired you (must) can use DirectX Tool kit, DirectX Tex and DirectXMath respectively for graphics, texture and math function ad structures.

http://directxtk.codeplex.com/

http://directxtex.codeplex.com/

http://msdn.microsoft.com/en-us/library/windows/desktop/ee418730.aspx

If you still want to use D3DX you must install the June 2010 DXSDK and manually configure the vs project: http://msdn.microsoft.com/en-us/library/windows/desktop/ee663275.aspx

Edited by Alessio1989, 02 March 2013 - 06:01 PM.

"Recursion is the first step towards madness." - "Skeggǫld, Skálmǫld, Skildir ro Klofnir!"
Direct3D 12 quick reference: https://github.com/alessiot89/D3D12QuickRef/

### #10/Jeff/  Members

Posted 04 March 2013 - 07:18 PM

As far as rendering the text to a texture, you use QueryInterface<T> as mentioned above to get an IDXGISurface1 pointer, and then pass that to ID2D1Factory::CreateDxgiSurfaceRenderTarget. Then you can just use that render target like the render target in my example above.

Example of render target creation:

// create the D3D11 texture

D3D11_TEXTURE2D_DESC texDesc = {};
texDesc.ArraySize = 1;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.Width = 512;
texDesc.Height = 512;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.MipLevels = 1;
ID3D11Texture2D *texture;
device->CreateTexture2D(&texDesc, NULL, &texture);

// create D2D render target using texture

ID2D1RenderTarget *renderTarget;
IDXGISurface1* dxgiSurface;
texture->QueryInterface<IDXGISurface1>(&dxgiSurface);
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
factory->CreateDxgiSurfaceRenderTarget(dxgiSurface, &props, &renderTarget);
dxgiSurface->Release();


For determining where the previous text ended on the screen...I think IDWriteFactory::CreateTextLayout and IDWriteTextLayout::GetMetrics might help. It looks like it can take care of wrapping text for you as well.

Edited by jrh2365, 04 March 2013 - 07:21 PM.

### #11BlackJoker  Members

Posted 06 March 2013 - 07:09 AM

Thanks a lot to all of you for your help! Everything seems work fine.

### #12BlackJoker  Members

Posted 07 March 2013 - 03:19 AM

I faced with another problem. Now D3D scene overlap D2D text in some cases. How to make D2D text always on top of D3D scene?

### #13BlackJoker  Members

Posted 10 March 2013 - 08:59 AM

Could someone help me with this question?

### #14/Jeff/  Members

Posted 11 March 2013 - 06:11 AM

Are you drawing text directly to the backbuffer with D2D? If so, its not using the depth buffer. You could try drawing the text last, or drawing the text to a texture first, and then drawing a quad using that texture.

### #15BlackJoker  Members

Posted 11 March 2013 - 06:27 AM

Are you drawing text directly to the backbuffer with D2D? If so, its not using the depth buffer. You could try drawing the text last, or drawing the text to a texture first, and then drawing a quad using that texture.

Yes, I am drawing directly to backbuffer. If I will draw to a texture will this texture be always on top of D3D scene independently of when I am drawing it?

### #16BlackJoker  Members

Posted 11 March 2013 - 06:51 AM

And one more question. Rendered text displaying not clear enough. I use antialiasing like this:



d2dRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
D2D1_ANTIALIAS_MODE anti;
anti = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
d2dRenderTarget->SetAntialiasMode(anti);


but text look like diffused (see attachment).

How to fix this and make text clear?

### #17/Jeff/  Members

Posted 11 March 2013 - 11:02 AM

Yes, I am drawing directly to backbuffer. If I will draw to a texture will this texture be always on top of D3D scene independently of when I am drawing it?

Here's a better explanation:

If you're just overlaying text on a scene, easiest would be to just draw it last. If for some reason you can't/don't want to draw all the text last, you could draw the text to a texture, and then draw a quad with that texture. You'll still need to draw that quad last, though, and you'd probably want to disable depth testing for that. (Note that this is also a bit less efficient because of the additional memory used by the texture, and overdraw.)

How to fix this and make text clear?

Not sure. If I have time, I'll see how it looks on my system later. Could you post the code you used to create the font?

### #18BlackJoker  Members

Posted 11 March 2013 - 11:14 AM

Not sure. If I have time, I'll see how it looks on my system later. Could you post the code you used to create the font?

Yes, here is my coe for that - it is just copy from yours



swapChain->GetBuffer(0, IID_PPV_ARGS(&BackBuffer11));

d3d11_Device->CreateRenderTargetView(BackBuffer11, NULL, &d3d11_RenderTargetView);
d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, NULL);

options.debugLevel = D2D1_DEBUG_LEVEL_ERROR;

swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackbuffer));
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
d2dfactory->CreateDxgiSurfaceRenderTarget(dxgiBackbuffer, props, &d2dRenderTarget);
dxgiBackbuffer->Release();

DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(DWriteFactory), (IUnknown**)(&DWriteFactory));

DWriteFactory->CreateTextFormat(
L"Cambria",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
14,
L"",
&textFormat);

d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &Brush);


and then I DrawText with this fuction:

In this code I dont use antialiasing, but there is no difference between using and not using it.



void D3D11::RenderText(WCHAR* text)
{
d2dRenderTarget->BeginDraw();
DWriteFactory->CreateTextLayout(text, wcslen(text), textFormat, 1000, 10, &textLayout);

D2D1_POINT_2F origin;
origin.x = 0;
origin.y = 0;
D2D1_DRAW_TEXT_OPTIONS op= D2D1_DRAW_TEXT_OPTIONS_NONE;
d2dRenderTarget->DrawTextLayout(origin,textLayout,Brush, op);
DWRITE_TEXT_METRICS textMetrix;
//получаем информацию о нарисованном тексте
textLayout->GetMetrics(&textMetrix);
//d2dRenderTarget->DrawText(text, wcslen(text), textFormat, D2D1::RectF(0, 0, 800, 600), Brush);
d2dRenderTarget->EndDraw();
textLayout->Release();
textLayout = NULL;
}


Edited by BlackJoker, 11 March 2013 - 04:31 PM.

### #19/Jeff/  Members

Posted 11 March 2013 - 06:25 PM

Ok, so two things:

First, it looks like you are using a font that you don't have. Cambria is a serif font, but the font in your screenshot is sans-serif, so I think it is failing to find the font you specified and uses a fallback instead.

Second, everything looks correct when I draw text with my code (see attachment). How are you sizing your window and backbuffer? If you're passing the same dimensions to CreateWindow and D3D11CreateDeviceAndSwapChain, that could be the problem because CreateWindow includes the size of the border in the dimensions. So then you end up with a window that is smaller than your backbuffer, and everything gets scaled and looks horrible.

You should use AdjustWindowRect to take the size of the border into account, passing the same style used to create the window (ex. WS_OVERLAPPEDWINDOW). Then when calling CreateWindow, you should pass rect.right - rect.left as the width, and rect.bottom - rect.top as the height, because AdjustWindowRect might make the left and top values negative. Relevant snippet from my code above:

RECT r = {0, 0, 800, 600};

HWND hWnd = CreateWindow(
(LPCSTR)a,
"Vector",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
r.right - r.left,
r.bottom - r.top,
NULL,
NULL,
hInstance,
NULL);


### #20BlackJoker  Members

Posted 12 March 2013 - 02:27 AM

jrh2365, your advice helped. Thanks a lot, but 1 question left (I hope  one).

I setup patch fro Win7 you wrote to fix interop D2D with D3D and now it works, but when I exit application, it crashes in "crt0dat.c" in



void __cdecl __crtExitProcess (
int status
)
{
__crtCorExitProcess(status);

/*
* or CorExitProcess isn't exported from mscoree.dll,
* or CorExitProcess returned (should never happen).
* Just call ExitProcess.
*/

ExitProcess(status);
}


here in the last line - ExitProcess(status)

If I comment the code for initialization of D2D, then no crashes occured. On Win 8 no crashes at all. Do you know how to fix that?

Edited by BlackJoker, 12 March 2013 - 03:39 AM.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.