I have a simple Window class and I use a function for WM_PAINT that clears the render target view and presents the final image.so there's not much into it but I get a crash on line FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f };
that says:0xC000041D: An unhandled exception was encountered during a user callback.
here's the window class:
class Win32Window : public WindowsWindow
{
public:
Win32Window(const WindowProps& props);
virtual ~Win32Window();
void OnUpdate() override;
unsigned int GetWidth() const override { return m_Data.Width; }
unsigned int GetHeight() const override { return m_Data.Height; }
void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; }
void SetVSync(bool enabled) override;
bool IsVSync() const override;
virtual void* GetNativeWindow() const override { return m_Window; }
private:
HWND m_Window;
RECT m_WindowRect;
HINSTANCE m_hInst;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual void Init(const WindowProps& props);
virtual void Shutdown();
};
the definitions:
Win32Window::Win32Window(const WindowProps& props)
{
HZ_PROFILE_FUNCTION();
Init(props);
}
Win32Window::~Win32Window()
{
HZ_PROFILE_FUNCTION();
Shutdown();
}
void Win32Window::Init(const WindowProps& props)
{
m_hInst = GetModuleHandle(0);
m_Data.WideCharacterTitle = props.WideCharacterTitle;
m_Data.Width = props.Width;
m_Data.Height = props.Height;
HZ_CORE_INFO("Creating window {0} ({1}, {2})",props.StringTypeTitle, props.Width, props.Height);
WNDCLASSEXW windowClass = {};
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = &WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = m_hInst;
windowClass.hIcon = ::LoadIcon(m_hInst, NULL);
windowClass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = m_Data.WideCharacterTitle;
windowClass.hIconSm = ::LoadIcon(m_hInst, NULL);
static ATOM atom = ::RegisterClassExW(&windowClass);
assert(atom > 0);
int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
RECT windowRect = { 0, 0, static_cast<LONG>(m_Data.Width), static_cast<LONG>(m_Data.Height) };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);
int windowWidth = windowRect.right - windowRect.left;
int windowHeight = windowRect.bottom - windowRect.top;
int windowX = std::max<int>(0, (screenWidth - windowWidth) / 2);
int windowY = std::max<int>(0, (screenHeight - windowHeight) / 2);
m_Window = ::CreateWindowExW(NULL, m_Data.WideCharacterTitle, m_Data.WideCharacterTitle, WS_OVERLAPPEDWINDOW, windowX, windowY, windowWidth, windowHeight, NULL, NULL, m_hInst, this);
assert(m_Window && "Failed to create window");
m_Context = GraphicsContext::Create(m_Window);
m_Context->Init();
::ShowWindow(m_Window, SW_SHOW);
::UpdateWindow(m_Window);
}
LRESULT Win32Window::MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
m_Context->RenderWindow();
break;
case WM_DESTROY:
::PostQuitMessage(0);
break;
default:
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
}
LRESULT Win32Window::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Win32Window* instance;
if (message == WM_CREATE)
{
instance = (Win32Window*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
instance->m_Window = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)instance);
}
else
{
instance = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
if (instance)
{
return instance->MainWndProc(hwnd, message, wParam, lParam);
}
return ::DefWindowProcW(hwnd, message, wParam, lParam);
}
void Win32Window::Shutdown()
{
DestroyWindow(m_Window);
m_Window = nullptr;
}
void Win32Window::OnUpdate()
{
m_Context->Update();
}
void Win32Window::SetVSync(bool enabled)
{
m_Data.VSync = enabled;
}
bool Win32Window::IsVSync() const
{
return m_Data.VSync;
}
m_Context is coming from the parent class, And also WindowProps that has some data for initializing the window .definition of m_Context->RenderWindow():
m_CommnadQueue = D3D12Core::Get().GetCommandQueue(D3D12_COMMAND_LIST_TYPE_DIRECT);
auto m_CommandList = m_CommnadQueue->GetCommandList();
m_CurrentBackBufferIndex = m_SwapChain->GetCurrentBackBufferIndex();
auto m_BackBuffer = D3D12Core::Get().m_BackBuffers[m_CurrentBackBufferIndex];
auto m_RTVDescriptorSize = D3D12Core::Get().GetDevice()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
m_CommandList->ResourceBarrier(1, &barrier);
FLOAT clearColor[] = { 0.2f, 0.4f, 0.6f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv(m_RTVDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), m_CurrentBackBufferIndex, m_RTVDescriptorSize);
m_CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr);
}
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_BackBuffer.Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
m_CommandList->ResourceBarrier(1, &barrier);
m_CommandList->Close();
ID3D12CommandList* const commandLists[] =
{
m_CommandList.Get()
};
D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex] = m_CommnadQueue->ExecuteCommandList(m_CommandList);
UINT syncInterval = m_VSync;
UINT presentFlags = m_TearingSupport && !m_VSync ? DXGI_PRESENT_ALLOW_TEARING : 0;
m_SwapChain->Present(syncInterval, presentFlags);
m_CommnadQueue->WaitForFenceValue(D3D12Core::Get().m_FenceValues[m_CurrentBackBufferIndex]);
}
If there is anything else that I should put in question pls tell me.You can shout at me for my dumbness if you want to but help me pls,thx. EDIT: debug layer:
#ifdef _DEBUG
ComPtr<ID3D12Debug> debugInterface;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface))))
{
debugInterface->EnableDebugLayer();
}
#endif
WaitForFenceValue
after every Present
is an extremely slow way to render in DirectX 12. You should generally cue 2-3 frames to the GPU rather than forcing the GPU to stall every frame. It is also highly problematic to have your WndProc
block, which is what happens here. Your WndProc
should always complete quickly as many hundreds of messages are processed a second for most applications.
Usually Direct3D rendering is not done within WM_PAINT
. For a number of examples of common render loops, see GitHub.