Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


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.

  • You cannot reply to this topic
20 replies to this topic

#1 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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 can`t 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.

 



Please, help me.

Attached Files



Sponsor:

#2 /Jeff/   Members   -  Reputation: 652

Like
2Likes
Like

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.


#3 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

Posted 02 March 2013 - 02:55 AM

I didn`t hear about this update. Is it for DirectX11 or for DirectX 11.1? Where I can read about it more detail?


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


#4 Alessio1989   Members   -  Reputation: 2060

Like
1Likes
Like

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.

"Software does not run in a magical fairy aether powered by the fevered dreams of CS PhDs"


#5 /Jeff/   Members   -  Reputation: 652

Like
2Likes
Like

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.lpszMenuName  = NULL;
	wcex.hCursor  = LoadCursor(NULL, IDI_APPLICATION);
	wcex.lpszClassName = "Vector";
	ATOM a = RegisterClassEx(&wcex);

	RECT r = {0, 0, 800, 600};
	AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);

	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;
	D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, &factory);

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


#6 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

Posted 02 March 2013 - 08:52 AM

I didn`t 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?



#7 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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 don`t 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.


#8 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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?



#9 Alessio1989   Members   -  Reputation: 2060

Like
1Likes
Like

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 don`t 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.

"Software does not run in a magical fairy aether powered by the fevered dreams of CS PhDs"


#10 /Jeff/   Members   -  Reputation: 652

Like
1Likes
Like

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.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
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.


#11 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

Posted 06 March 2013 - 07:09 AM

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



#12 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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?



#13 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

Posted 10 March 2013 - 08:59 AM

Could someone help me with this question?



#14 /Jeff/   Members   -  Reputation: 652

Like
1Likes
Like

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.



#15 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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?



#16 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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?

Attached Thumbnails

  • Text.png


#17 /Jeff/   Members   -  Reputation: 652

Like
0Likes
Like

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?



#18 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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;
	D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, options, &d2dfactory);

	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 don`t 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   -  Reputation: 652

Like
1Likes
Like

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};
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);

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

 

 

AdjustWindowRect

Attached Thumbnails

  • text.png


#20 BlackJoker   Members   -  Reputation: 547

Like
0Likes
Like

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

        /*
         * Either mscoree.dll isn't loaded,
         * 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.



PARTNERS