Rendering to a Child Window w/ D3D & Win32

Started by
7 comments, last by markypooch 6 years, 11 months ago

Hey Guys,

Hoping there are some Win32 guys out there since I have a bit of an issue. So I'm rendering to a child window of my Win32 application with D3D11. For the most part, everything is well, and good. However when I go to actually render some geometry to the screen my backbuffer flashes. At first I thought it was Z-Fighting, however having ruled that out, it almost looks as if there are two presents going on.

The one that I know about, the call to the swapChains method to present the backbuffer, and another one buried in Win32 callback code somewhere. I'm wondering if there is a simple fix for this. I don't need the application to run at anything more than 20fps to be completely honest. So throw some suggestions at me, if ya got them.

The child window I render to:


hPanel = CreateWindowEx(NULL, L"RR", L"None", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 40, 20, 500, 500, hWnd, nullptr, nullptr, nullptr);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDC_BUTTON1:
			//If Button pressed, retrieve text from textArea, and locate it in wide string
			text.resize(GetWindowTextLength(hEdit)+1);
			GetWindowText(hEdit, &text[0], text.size());
			SetWindowText(hEdit, L"");
			break;
		}
		break;
	case WM_PAINT:
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}

I'm a bit of a Win32 noob. One common suggestion I see is to throw the D3D rendering code into WM_PAINT case, but I was wondering if there are other ways.

Thanks,

Marcus

Advertisement

Out of curiosity, what OS are you running on?

My understanding of how child windows work is that they share the same backing surface as the parent window, and they just get asked to render into a small portion of it with a clipping rect. So the two presents that you'd be seeing would be one from your parent window, and one from your child window.

I don't necessarily know the answer, but I have two experiments you can try if you're on Win8+:

1. What happens if you add WS_EX_LAYERED to the window style?

2. What happens if you use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL?

Take the WM_PAINT out of there to start, you're returning 0 saying you handled repainting the window.

https://msdn.microsoft.com/en-us/library/windows/desktop/dd145213(v=vs.85).aspx

See if that makes a difference, I think it might be your issue as I've had that previously.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Hey guys,

thanks for the follow up. Once I'm back at my desk, i'll make these changes.

Out of curiosity, what OS are you running on?

This build is on a Win10 box.

1. What happens if you add WS_EX_LAYERED to the window style?

2. What happens if you use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL?

I'll try those changes. I think right now I didn't specify any particular swap effect in my chain, so i'll give both a shot, and report back how it goes.

Take the WM_PAINT

I added that for placing my D3D render code into. I had the issue beforehand, however, this was admist changes so removing may now yield a different result, I'll let you know.

Thanks Guys!

Marcus

Hey,

So I removed the WM_PAINT case, and the issue persisted, same for the WS_EX_LAYERED. I added the additional swap effect to the structure, and now it only renders one frame to the backbuffer, and just stops. So it's very possible I just am missing something in regards to how this particular swap effect is supposed to work.

Here goes my chain creation. Interestingly enough, if I add a 1 to my present method to synch with the v-blank, I see one frame (that quickly vanishes), otherwise I see nothing at all.


	DXGI_SWAP_CHAIN_DESC swapDesc = {};
	swapDesc.BufferCount = 2;
	swapDesc.BufferDesc.Height = height;
	swapDesc.BufferDesc.Width = width;
	swapDesc.BufferDesc.RefreshRate.Numerator = RR; 
	swapDesc.BufferDesc.RefreshRate.Denominator = 1;
	swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
	swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
	swapDesc.OutputWindow = hWnd; 
	swapDesc.SampleDesc.Count = 1;
	swapDesc.SampleDesc.Quality = 0;
	swapDesc.Windowed = true;

	hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &swapDesc, &swapChain, &device, nullptr, &deviceContext);
	if (FAILED(hr)) throw GetLastError();

	ID3D11Texture2D *swapTexture;
	hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&swapTexture);
	if (FAILED(hr)) throw GetLastError();
	hr = device->CreateRenderTargetView(swapTexture, nullptr, &rtv);
	if (FAILED(hr)) throw GetLastError();

Right, FLIP_SEQUENTIAL requires you to call OMSetRenderTargets again every frame.

The WS_EX_LAYERED style is incompatible with DirectX processing (or was a few years ago).

Okay, but don't use WM_PAINT to render in either. That is for updating win32 controls (custom drawn etc)

Instead in your main loop, process all the windows events then run your game update then render functions.

Can we see your main loop? That might help a lot. Are you using PeekMessage() or GetMessage()? etc.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Jesse, you rock! :^) I added the WM_EX_LAYERED, and the new swap effect to the chain (after adding the new per frame call of OMSetRenderTargets), and that did it!

A good catch on the WM_PAINT case I left in there as I'm sure that wasn't helping matters. The present seems to be synched now across the parent, and child window.

Thanks a bunch guys!

Marcus

This topic is closed to new replies.

Advertisement