Skip to main content
GameDev.net gamedev.net
🔒 Locked

Win32/D3D10 Window not painting properly

Started by ds2k5 Mar 7, 2012 at 11:04 PM 7 replies 3.2k views
Original Post
ds2k5
ds2k5

I'm having an annoying problem in a win32/d3d10 application. I'm using D3D to render a texture to the window, which worked fine as long as I kept constantly rendering, however I chose to render only when receiving WM_PAINT messages. Now when I start the application, the rendered texture is briefly shown but disappears the next instant, leaving a blank window. At first I thought there was something wrong with the rendering code, but user generated InvalidateRect calls (e.g. on mouse click/move etc.) get the texture rendered properly. Unfortunately, as soon as the window loses focus it becomes blank again.

I'm desperate, as after hours of research and debugging, I'm not really sure what is causing this. I suspect that it may have something to do with the validation of the window's update region, since
1.) ValidateRect won't actually validate the region (GetUpdateRect returns the same rectangle before and after ValidateRect)
2.) If I don't call either Begin-/EndPaint or DefWindowProc on WM_PAINT, the rendering works fine, however I keep getting WM_PAINT messages about once every second, because the update region doesn't get validated.

Although I wonder why ValidateRect doesn't work (as I'd like to avoid Begin-/EndPaint), when it seems to work for everyone else, I'm not sure it's actually the cause of my problem. It's probably some trivial issue, but I'm clueless and hoping that anyone else has encountered and solved it. Any hints are greatly appreciated.


[..]

case WM_ERASEBKGND:

return 1;

case WM_PAINT:

render();

break;

[..]

return DefWindowProc( hWnd, uMsg, wParam, lParam );

That's how the WM_PAINT and WM_ERASEBKGND messages get handled. The render() method would probably be more confusing than helpful and seems to work anyway.

Endurion
Endurion
From MSDN about WM_PAINT:

Return value

An application returns zero if it processes this message.


So don't pass WM_PAINT on to DefWindowProc, but return 0. In any case, you either need to call ValidateRect, or BeginPaint/EndPaint to avoid getting swamped with WM_PAINTs.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
ds2k5
ds2k5

From MSDN about WM_PAINT:

Return value

An application returns zero if it processes this message.


So don't pass WM_PAINT on to DefWindowProc, but return 0. In any case, you either need to call ValidateRect, or BeginPaint/EndPaint to avoid getting swamped with WM_PAINTs.


I should have mentioned this, using BeginPaint/EndPaint and returning 0 results in the exact same behavior as passing the message to DefWindowProc. ValidateRect won't work at all, as I've mentioned, if I use it the window doesn't actually get validated and keeps receiving WM_PAINTs.

Edit: Main problem fixed. I didn't handle WM_NCPAINT, a simple "return 0;" fixed the blank window issue. Unfortunately ValidateRect still won't work and I'd prefer using it instead of BeginPaint/EndPaint.
Endurion
Endurion
How exactly are you drawing to your window and invalidating it?

You should never need to handle WM_NCPAINT, just pass it on to DefWindowProc.
It may work for now but there seems to be another problem lurking in there.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
ds2k5
ds2k5

How exactly are you drawing to your window and invalidating it?

You should never need to handle WM_NCPAINT, just pass it on to DefWindowProc.
It may work for now but there seems to be another problem lurking in there.


The drawing part is mostly put together from several tutorials as it's my first time working with DX10. I use Direct2D to render to a texture which is then used to render a quad with. That's what the method looks like:

void Window::render()
{
// Direct2D rendering
m_pRenderTarget->BeginDraw();
m_pRenderTarget->Clear( D2D1::ColorF( 0.0f, 0.0f, 1.0f, 0.5f ) );
// <unnecessary render code>
m_pRenderTarget->EndDraw();


// Direct3D rendering
m_pevWorld->SetMatrix( m_matWorld );
m_pevView->SetMatrix( m_matView );
m_pevProjection->SetMatrix( m_matProjection );

m_pDevice->ClearRenderTargetView( m_pRenderTargetView, D3DXCOLOR( 0.0f, 0.0f, 0.0f, 0.0f ) );

D3D10_TECHNIQUE_DESC techDesc;
m_pTechnique->GetDesc( &techDesc );
for( UINT i = 0; i < techDesc.Passes; ++i )
{
m_pTechnique->GetPassByIndex( i )->Apply( 0 );
m_pDevice->Draw( 4, 0 );
}

m_pSwapChain->Present( 1, 0 );
}


And this is everything being called on WM_PAINT. As for invalidating, so far I've only done it for testing.

case WM_RBUTTONDOWN:
InvalidateRect( hWnd, NULL, false );
break;


If the window needs repainting I call the render() method directly so it's only the system that actually invalidates the window.
Endurion
Endurion
I assume your call to ValidateRect looks exactly like InvalidateRect?

e.g.: ValidateRect( hWnd, NULL );
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
ds2k5
ds2k5
Exactly.

case WM_PAINT:
PAINTSTRUCT ps;
BeginPaint( hWnd, &ps );
render();
EndPaint( hWnd, &ps );
//ValidateRect( hWnd, NULL );
//RECT rect;
//if( GetUpdateRect( hWnd, ▭, false ) != 0 )
//{
// OutputDebugString( L"not validated\n" );
//}
//else
//{
// OutputDebugString( L"validated\n" );
//}
return 0;


If I use the commented part instead of BeginPaint/EndPaint I get only "not validated" output.
Endurion
Endurion
Hmm, can you provide a minimal sample where the problem occurs? The problem should also appear without any D3D code.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
ds2k5
ds2k5
While copying the essential code I actually found the problem myself. It's a trivial issue, just as I thought. One of the tutorials I used was on making transparent windows with Direct3D9Ex and DWM without using WS_EX_LAYERED, instead it said to use WS_EX_COMPOSITED, which I did. I thought I had checked if other styles were possible, but it seems I have not, since exchanging WS_EX_COMPOSITED for WS_EX_APPWINDOW fixed validation and transparency is still working.

Now I feel kind of stupid for not trying to reproduce the issue before, as copying the essential code wasn't exactly the most difficult thing to do. So thank you for asking me to do it, and the help in general. smile.png


[spoiler]
It doesn't matter anymore, but I've copied the code that produces the problem.

LRESULT WINAPI wndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
ValidateRect( hWnd, NULL );
RECT rect;
if( GetUpdateRect( hWnd, ▭, false ) != 0 )
{
OutputDebugString( L"not validated\n" );
}
else
{
OutputDebugString( L"validated\n" );
}
return 0;
case WM_KEYDOWN:
if( LOWORD( wParam ) == VK_ESCAPE )
{
SendMessage( hWnd, WM_CLOSE, NULL, NULL );
}
break;
}

return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, INT )
{
WNDCLASSEX wc = {
sizeof( WNDCLASSEX ),
NULL,
wndProc,
NULL,
NULL,
hInstance,
LoadIcon( NULL, IDI_APPLICATION ),
LoadCursor( NULL, IDC_ARROW ),
NULL,
NULL,
L"FunnyWndClassName",
LoadIcon( NULL, IDI_APPLICATION ),
};

RegisterClassEx( &wc );

HWND hWnd = CreateWindowEx(
WS_EX_COMPOSITED, // exchange for WS_EX_APPWINDOW to fix validation
L"FunnyWndClassName",
L"FunnyWndName",
WS_POPUP | WS_SIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
600,
400,
NULL,
NULL,
hInstance,
NULL );

ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );

MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}

return 0;
}
[/spoiler]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.