Advertisement

Sharing surface with ID2D1DCRenderTarget created by CreateDCRenderTarget

Started by February 05, 2018 01:15 PM
4 comments, last by SoldierOfLight 6 years, 11 months ago
I have found an example here:
 
 
about sharing surfaces/textures created by DX11 into the ID2D1DCRenderTarget, however the above example is based on SwapChain bound to a window (hwnd)
 
What I need is to draw a shared texture into GDI as this is the only plugin interface in an old software I have. Any ideas ?
 
Here is what I do.
 

SharedSurface::SharedSurface():
{

	//Initialize the ID2D1Factory object
	D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
	//D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &pD2DFactory);
	//initialize the ID2D1DCRenderTarget
	D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
		D2D1_RENDER_TARGET_TYPE_HARDWARE, // D2D1_RENDER_TARGET_TYPE_DEFAULT,
		D2D1::PixelFormat(
			DXGI_FORMAT_B8G8R8A8_UNORM,
			D2D1_ALPHA_MODE_PREMULTIPLIED),
		0,
		0,
		D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
		D2D1_FEATURE_LEVEL_DEFAULT
	);
	HRESULT hr = pD2DFactory->CreateDCRenderTarget(&props, &pRT);

	DWORD createDeviceFlags = 0;
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;

	ID3D11DeviceContext* context;
	D3D_FEATURE_LEVEL fl;

    DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory( &sd, sizeof( sd ) );
	sd.BufferCount = 1;
	sd.BufferDesc.Width = width;
	sd.BufferDesc.Height = height;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHARED;
	sd.OutputWindow = 0; // g_hWnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = FALSE, // TRUE;		

	hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE,
		nullptr, createDeviceFlags, nullptr,
		0, D3D11_SDK_VERSION, &sd, &pSwapChain, &mDevice, &fl, &context);

	hr = m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));		

}

bool SharedSurface::CreateTexture(ID3D11Device* device, UINT width, UINT height)
{
	HRESULT hr;
	D3D11_TEXTURE2D_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.Width = width;
	desc.Height = height;
	desc.MipLevels = 1;
	desc.ArraySize = 1;
	desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	desc.SampleDesc.Count = 1;

	desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; // D3D11_RESOURCE_MISC_SHARED; // 
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	desc.CPUAccessFlags = 0; // D3D11_CPU_ACCESS_READ; // 0;

	if (device != nullptr)
		mDevice = device;

	hr = mDevice->CreateTexture2D(&desc, NULL, &pTexture);

	IDXGIResource * pDXGIResource = NULL;
	hr = pTexture->QueryInterface(__uuidof(IDXGIResource), (void **)&pDXGIResource);

	if SUCCEEDED(hr)
	{

		hr = pDXGIResource->GetSharedHandle(&sharedHandle);
		pDXGIResource->Release();

		if SUCCEEDED(hr)
		{
			hr = pTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
				(LPVOID*)&pMutex);

		}
	}


	hr = pTexture->QueryInterface(__uuidof(IDXGISurface), (void **)&pSurface);

	FLOAT dpiX;
    FLOAT dpiY;
    pD2DFactory->GetDesktopDpi(&dpiX, &dpiY);

	D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE/*D2D1_RENDER_TARGET_TYPE_DEFAULT*/, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),dpiX,dpiY);

	hr = pD2DFactory->CreateDxgiSurfaceRenderTarget(pBackBuffer,&props,	&pBackBufferRT);

	DXGI_SURFACE_DESC sdesc;
	D2D1_BITMAP_PROPERTIES bp;
	ZeroMemory(&bp, sizeof(bp));
	pSurface->GetDesc(&sdesc);
	bp.pixelFormat = D2D1::PixelFormat(sdesc.Format, D2D1_ALPHA_MODE_PREMULTIPLIED);

	hr = pBackBufferRT->CreateSharedBitmap(__uuidof(ID3D11Texture2D), pSurface,&bp, &pBitmap);

	return SUCCEEDED(hr);

}

void SharedSurface::Draw()
{
	pBackBufferRT->BeginDraw();
	pBackBufferRT->DrawBitmap(pBitmap);
	pBackBufferRT->EndDraw();
	pBackBufferRT->Present();

}
void SharedSurface::BindDC(HDC hdc, int width, int height)
{
	RECT rct;
	rct.top = 0;
	rct.left = 0;
	rct.right = width;
	rct.bottom = height;
	pRT->BindDC(hdc, &rct);
}

// HOW TO EXCHANGE between pBackBufferRT and pRT ? 

 

It looks like CreateDxgiSurfaceRenderTarget cannot be used with D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE and CreateSharedBitmap cannot be used with ID2D1DCRenderTarget as it must be used with render target created by CreateDxgiSurfaceRenderTarget , so looks there is no straight way to do it. Any tricks ?

Advertisement

I am a bit unclear what you are trying to do. You can do 2 totally seperate things with directx2d in your directx3d program.

1. You can use directx2d to write to the swapchain backbuffer.

2. You can use direct2d to write to a texturebuffer that you use as a SRV in your 3d pipeline. This has nothing to do with the swapchain. For example you might want your pixel shader to use this texture to display some text on the side of an object.

See here for different things you can do  - https://msdn.microsoft.com/en-gb/library/windows/desktop/dd370966(v=vs.85).aspx

The scenario is the following.

I have quite old app using dx9 which allows plugin integration. Unfortunately the plugin integration is through GDI, so I receive Paint callback with HDC. What I do is drawing into Texture2D using DX11 in another process and share the texture with GDI plugin. It works fine when I share the texture bits through CPU. Now, I want to use GPU only and use the texture sharing between DX11 and GDI so I tried to create ID2D1DCRenderTarget   but that I cannot link with any shared surface ...

You'd need to create a swapchain on the corresponding HWND and Present() to copy the bits, or create a GDI_COMPATIBLE surface and use the IDXGISurface1::GetDC/ReleaseDC methods to get a second DC, and use GDI to do the copy.

This topic is closed to new replies.

Advertisement