Reputation: 12985
Remeber: FRAPS + D3D11_CREATE_DEVICE_DEBUG +
SampleDesc.Count > 1
don't mix.
I'm really new to DX... as in a week old. But the problem is very easy to describe, even with my limited lingo and understanding. I'm keeping the DEBUG
layer on as it provides valuable feedback. But in turn it creates a problem I can't overcome. I've spent 1 day pulling hairs strand by strand.
If I create a D3D11
device with:
vSwapChainDesc.SampleDesc.Count = 4;
vSwapChainDesc.SampleDesc.Quality = 3;
... it crashes on the final ->Release()
, no matter which object it is. The exact same DAMN code with:
vSwapChainDesc.SampleDesc.Count = 1;
vSwapChainDesc.SampleDesc.Quality = 0;
... cleans up COM references smoothly. Not to mention that both variants work fine in Release
without DEBUG
flag.
In the Output
, I get some cryptic error saying live children without parents
. But I have only 5 COM objects I use with a COM wrapper.
So I removed the COM wrapper, doing the ->Release()
and = nullptr
by hand for each of them. It is IMPOSSIBLE to be releasing something by mistake, IMO. And on the final ->Release()
it says it hit a breakpoint.
So... has anyone else encountered such behavior? I don't think I can get an answer unless someone else went through the exact same thing. It's so weird...
// Uncomment this and it all works... like magic!
// #undef _DEBUG
#pragma region Includes
#include <stdio.h>
#include <conio.h>
#include <map>
#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "dxgi.lib")
#pragma comment (lib, "d3d11.lib")
#pragma endregion
#pragma region Com Helpers
// track the refcounts on ->Release() :)
std::map<std::string, int> g_ComCounter;
template <typename Interface_t>
Interface_t** ComRelease(Interface_t** aPointer, LPCSTR aName) {
if(!aPointer) {
DebugBreak();
}
if(*aPointer) {
// save refcount for debug
g_ComCounter[aName] = (*aPointer)->Release();
*aPointer = nullptr;
}
printf("Destroyed %p (%s:%d).\r\n", *aPointer, aName, g_ComCounter[aName]);
return aPointer;
}
#define COM_RELEASE(Pointer) ComRelease(&Pointer, #Pointer)
template <typename Interface_t>
Interface_t** ComPointer(Interface_t** aPointer, LPCSTR aName) {
if(!aPointer) {
DebugBreak();
}
if(*aPointer) {
// save refcount for debug
g_ComCounter[aName] = (*aPointer)->Release();
*aPointer = nullptr;
}
printf("Prepared %p (%s:%d).\r\n", *aPointer, aName, g_ComCounter[aName]);
// Object is being Acquired
return aPointer;
}
#define COM_POINTER(Pointer) ComPointer(&Pointer, #Pointer)
#pragma endregion
#pragma region Window Proc
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT vPainStruct = { 0 };
HDC vDc(nullptr);
switch(uMessage) {
case WM_PAINT:
vDc = BeginPaint(hWnd, &vPainStruct);
EndPaint(hWnd, &vPainStruct);
return FALSE;
break;
case WM_ERASEBKGND:
// Don't erase background!
return TRUE;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
#pragma endregion
#ifdef _CONSOLE
int wmain(int aArgc, const WCHAR* aArgv[]) {
#else
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
#endif
#pragma region Variables
HINSTANCE vInstance = GetModuleHandle(nullptr);
HWND vHwnd = nullptr;
D3D_DRIVER_TYPE vDriverType = D3D_DRIVER_TYPE_UNKNOWN;
D3D_FEATURE_LEVEL vFeatureLevel = D3D_FEATURE_LEVEL_11_0;
IDXGIFactory *vDxgiFactory = nullptr;
IDXGIAdapter *vDxgiAdapter = nullptr;
ID3D11Device *vD3dDevice = nullptr;
ID3D11DeviceContext *vD3dContext = nullptr;
IDXGISwapChain *vSwapChain = nullptr;
ID3D11Texture2D *vBackBuffer(nullptr);
ID3D11RenderTargetView *vRenderTargetView = nullptr;
#ifdef _DEBUG
ID3D11Debug *vDebugger = nullptr;
ID3D11InfoQueue *vInfoQueue = nullptr;
#endif
#pragma endregion
#pragma region Init Window
// Register class
WNDCLASSEX vWndClass;
ZeroMemory(&vWndClass, sizeof(vWndClass));
vWndClass.cbSize = sizeof(WNDCLASSEX);
vWndClass.style = 0; // CS_HREDRAW | CS_VREDRAW (draw in loop, no need for WM_PAINT)
vWndClass.lpfnWndProc = WndProc;
vWndClass.cbClsExtra = 0;
vWndClass.cbWndExtra = 0;
vWndClass.hInstance = vInstance;
vWndClass.hIcon = 0;
vWndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
vWndClass.hbrBackground = nullptr;
vWndClass.lpszMenuName = nullptr;
vWndClass.lpszClassName = L"D3d11Window";
vWndClass.hIconSm = 0;
if(!RegisterClassEx(&vWndClass)) {
DebugBreak();
return 0;
}
// Create window
RECT vWindowRect = { 0, 0, 640, 480 };
AdjustWindowRect(&vWindowRect, WS_OVERLAPPEDWINDOW, FALSE);
vHwnd = CreateWindowEx(
0, vWndClass.lpszClassName, L"D3D11", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
vWindowRect.right - vWindowRect.left, vWindowRect.bottom - vWindowRect.top,
nullptr, nullptr, vInstance,
nullptr);
if(!vHwnd) {
DebugBreak();
return 0;
}
ShowWindow(vHwnd, SW_SHOWDEFAULT);
#pragma endregion
#pragma region Initialization
RECT vClientRect = { 0 };
GetClientRect(vHwnd, &vClientRect);
UINT vWidth = vClientRect.right - vClientRect.left;
UINT vHeight = vClientRect.bottom - vClientRect.top;
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)COM_POINTER(vDxgiFactory)))) {
DebugBreak();
return 0;
}
if(FAILED(vDxgiFactory->EnumAdapters(0, COM_POINTER(vDxgiAdapter)))) {
DebugBreak();
return 0;
}
D3D_FEATURE_LEVEL vRequestedFeatureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
// D3D_FEATURE_LEVEL_10_1,
// D3D_FEATURE_LEVEL_10_0
};
UINT vNumFeatureLevels = ARRAYSIZE(vRequestedFeatureLevels);
UINT vDeviceFlags = 0;
#ifdef _DEBUG
vDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
if(FAILED(D3D11CreateDevice(
vDxgiAdapter,
vDriverType,
nullptr,
vDeviceFlags,
vRequestedFeatureLevels,
vNumFeatureLevels,
D3D11_SDK_VERSION,
COM_POINTER(vD3dDevice),
&vFeatureLevel,
COM_POINTER(vD3dContext)))) {
return 0;
}
#ifdef _DEBUG
if(FAILED(vD3dDevice->QueryInterface(__uuidof(ID3D11Debug), (LPVOID*)COM_POINTER(vDebugger)))) {
return 0;
}
if(FAILED(vDebugger->QueryInterface(__uuidof(ID3D11InfoQueue), (LPVOID*)COM_POINTER(vInfoQueue)))) {
return 0;
}
vInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
vInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
vDebugger->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
#endif
UINT vMsaaQuality = 0;
if(FAILED(vD3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &vMsaaQuality)) || (vMsaaQuality < 1)) {
return 0;
}
printf("MsaaQuality: %d for 4\r\n", vMsaaQuality);
DXGI_SWAP_CHAIN_DESC vSwapChainDesc;
ZeroMemory(&vSwapChainDesc, sizeof(vSwapChainDesc));
vSwapChainDesc.BufferCount = 2;
vSwapChainDesc.BufferDesc.Width = vWidth;
vSwapChainDesc.BufferDesc.Height = vHeight;
vSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
vSwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
vSwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
vSwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
vSwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
vSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
vSwapChainDesc.SampleDesc.Count = 4; // set 1 for the code to work vSwapChainDesc.SampleDesc.Quality = vMsaaQuality - 1;
vSwapChainDesc.OutputWindow = vHwnd;
vSwapChainDesc.Windowed = true;
vSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
vSwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
if(FAILED(vDxgiFactory->CreateSwapChain(vD3dDevice, &vSwapChainDesc, COM_POINTER(vSwapChain)))) {
return 0;
}
if(FAILED(vSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)COM_POINTER(vBackBuffer)))) {
return 0;
}
if(FAILED(vD3dDevice->CreateRenderTargetView(vBackBuffer, nullptr, COM_POINTER(vRenderTargetView)))) {
return 0;
}
vD3dContext->OMSetRenderTargets(1, &vRenderTargetView, nullptr);
D3D11_VIEWPORT vViewport = { 0 };
vViewport.Width = static_cast<FLOAT>(vWidth);
vViewport.Height = static_cast<FLOAT>(vHeight);
vViewport.MinDepth = D3D11_MIN_DEPTH;
vViewport.MaxDepth = D3D11_MAX_DEPTH;
vViewport.TopLeftX = 0;
vViewport.TopLeftY = 0;
vD3dContext->RSSetViewports(1, &vViewport);
#pragma endregion
#pragma region Game Loop
MSG vMessage = { 0 };
while(WM_QUIT != vMessage.message) {
while(PeekMessage(&vMessage, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&vMessage);
DispatchMessage(&vMessage);
}
if(WM_QUIT == vMessage.message) {
break;
}
#pragma region Render
float vClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
vD3dContext->ClearRenderTargetView(vRenderTargetView, vClearColor);
vSwapChain->Present(true, 0); // vsync
#pragma endregion
}
#pragma endregion
#pragma region Cleanup
if(vSwapChain) {
vSwapChain->SetFullscreenState(false, nullptr);
}
if(vD3dContext) {
vD3dContext->ClearState();
}
COM_RELEASE(vRenderTargetView);
COM_RELEASE(vBackBuffer);
COM_RELEASE(vSwapChain);
COM_RELEASE(vD3dContext);
COM_RELEASE(vD3dDevice);
COM_RELEASE(vDxgiFactory);
COM_RELEASE(vDxgiAdapter);
#ifdef _DEBUG
COM_RELEASE(vDebugger);
COM_RELEASE(vInfoQueue);
#endif
printf("\r\nREF COUNTS AFTER RELEASE():\r\n");
for(const auto& vComCount : g_ComCounter) {
printf("%s:%d\r\n", vComCount.first.c_str(), vComCount.second);
}
#pragma endregion
_getch();
return (int)vMessage.wParam;
}
HELP!
If you want me to comment the code to better explain the logic, I will. I get comments mentioning things that are clearly explain the question and code... Maybe I'm not clear enough.
Maybe there's some kind of release function internal to certain objects I'm not calling. Maybe I'm doing something out of order or really wrong. But I got this from a reputable website. And it matches the Hello DirectX!
code in the books I'm currently indulging myself with.
This snippet is stripped down and minimalistic. It's a trimmed version of a more complex one while trying to identify the problem. Plus I removed all OOP to have it in one block of code easy to follow.
Now there's a final question: Is there another way to smooth lines except this
SampleDesc
one?
PS: It's Windows 7 x64, VS 2013 + 2014 CTP. And the card supports it as it works (edges are smooth) in both debug and release mode. It's only the final release that fails in debug mode.
Upvotes: 3
Views: 1123
Reputation: 8727
I don't know why your code crashes, but I would like to share some of my experiences of DirectX programming based on your code, :)
A more clean code as below, you will get rid of the complexity COM stuff and focus on the code logic to check the crash.
#define DEBUG
#pragma region Includes
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <d3d11.h>
#pragma comment (lib, "dxgi.lib")
#pragma comment (lib, "d3d11.lib")
#pragma endregion
// Release COM object
#define SAFE_RELEASE(P) if(P){ P->Release(); P = NULL;}
#pragma region Window Proc
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT vPainStruct = { 0 };
HDC vDc(nullptr);
switch(uMessage) {
case WM_PAINT:
vDc = BeginPaint(hWnd, &vPainStruct);
EndPaint(hWnd, &vPainStruct);
return FALSE;
break;
case WM_ERASEBKGND:
// Don't erase background!
return TRUE;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
#pragma endregion
int main() {
#pragma region Variables
HINSTANCE vInstance = GetModuleHandle(nullptr);
HWND vHwnd = nullptr;
D3D_DRIVER_TYPE vDriverType = D3D_DRIVER_TYPE_UNKNOWN;
D3D_FEATURE_LEVEL vFeatureLevel = D3D_FEATURE_LEVEL_11_0;
IDXGIFactory *vDxgiFactory = NULL;
IDXGIAdapter *vDxgiAdapter = nullptr;
ID3D11Device *vD3dDevice = nullptr;
ID3D11DeviceContext *vD3dContext = nullptr;
IDXGISwapChain *vSwapChain = nullptr;
ID3D11Texture2D *vBackBuffer = NULL;
ID3D11RenderTargetView *vRenderTargetView = nullptr;
#ifdef _DEBUG
ID3D11Debug *vDebugger = nullptr;
ID3D11InfoQueue *vInfoQueue = nullptr;
#endif
#pragma endregion
#pragma region Init Window
// Register class
WNDCLASSEX vWndClass;
ZeroMemory(&vWndClass, sizeof(vWndClass));
vWndClass.cbSize = sizeof(WNDCLASSEX);
vWndClass.style = 0; // CS_HREDRAW | CS_VREDRAW (draw in loop, no need for WM_PAINT)
vWndClass.lpfnWndProc = WndProc;
vWndClass.cbClsExtra = 0;
vWndClass.cbWndExtra = 0;
vWndClass.hInstance = vInstance;
vWndClass.hIcon = 0;
vWndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
vWndClass.hbrBackground = nullptr;
vWndClass.lpszMenuName = nullptr;
vWndClass.lpszClassName = L"D3d11Window";
vWndClass.hIconSm = 0;
if(!RegisterClassEx(&vWndClass)) {
DebugBreak();
return 0;
}
// Create window
RECT vWindowRect = { 0, 0, 640, 480 };
vHwnd = CreateWindowEx(
0, vWndClass.lpszClassName, L"D3D11", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
vWindowRect.right - vWindowRect.left, vWindowRect.bottom - vWindowRect.top,
nullptr, nullptr, vInstance,
nullptr);
if(!vHwnd) {
DebugBreak();
return 0;
}
ShowWindow(vHwnd, SW_SHOWDEFAULT);
#pragma endregion
#pragma region Initialization
RECT vClientRect = { 0 };
GetClientRect(vHwnd, &vClientRect);
UINT vWidth = vClientRect.right - vClientRect.left;
UINT vHeight = vClientRect.bottom - vClientRect.top;
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&vDxgiFactory)))) {
DebugBreak();
return 0;
}
if(FAILED(vDxgiFactory->EnumAdapters(0, &vDxgiAdapter))) {
DebugBreak();
return 0;
}
D3D_FEATURE_LEVEL vRequestedFeatureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
// D3D_FEATURE_LEVEL_10_1,
// D3D_FEATURE_LEVEL_10_0
};
UINT vNumFeatureLevels = ARRAYSIZE(vRequestedFeatureLevels);
UINT vDeviceFlags = 0;
#ifdef _DEBUG
vDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
if(FAILED(D3D11CreateDevice(
vDxgiAdapter,
vDriverType,
nullptr,
vDeviceFlags,
vRequestedFeatureLevels,
vNumFeatureLevels,
D3D11_SDK_VERSION,
&vD3dDevice,
&vFeatureLevel,
&vD3dContext))) {
return 0;
}
UINT vMsaaQuality = 0;
if(FAILED(vD3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &vMsaaQuality)) || (vMsaaQuality < 1)) {
return 0;
}
printf("MsaaQuality of max %d supported for count 4\r\n", vMsaaQuality);
DXGI_SWAP_CHAIN_DESC vSwapChainDesc;
ZeroMemory(&vSwapChainDesc, sizeof(vSwapChainDesc));
vSwapChainDesc.BufferCount = 2;
vSwapChainDesc.BufferDesc.Width = vWidth;
vSwapChainDesc.BufferDesc.Height = vHeight;
vSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
vSwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
vSwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
vSwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
vSwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
vSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
vSwapChainDesc.SampleDesc.Count = 4; // set 1 to work
vSwapChainDesc.SampleDesc.Quality = vMsaaQuality - 1;
vSwapChainDesc.OutputWindow = vHwnd;
vSwapChainDesc.Windowed = true;
vSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
vSwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
if(FAILED(vDxgiFactory->CreateSwapChain(vD3dDevice, &vSwapChainDesc, &vSwapChain))) {
return 0;
}
if(FAILED(vSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&vBackBuffer))) {
return 0;
}
if(FAILED(vD3dDevice->CreateRenderTargetView(vBackBuffer, nullptr, &vRenderTargetView))) {
return 0;
}
vD3dContext->OMSetRenderTargets(1, &vRenderTargetView, nullptr);
D3D11_VIEWPORT vViewport = { 0 };
vViewport.Width = static_cast<FLOAT>(vWidth);
vViewport.Height = static_cast<FLOAT>(vHeight);
vViewport.MinDepth = D3D11_MIN_DEPTH;
vViewport.MaxDepth = D3D11_MAX_DEPTH;
vViewport.TopLeftX = 0;
vViewport.TopLeftY = 0;
vD3dContext->RSSetViewports(1, &vViewport);
#pragma endregion
#pragma region Game Loop
MSG vMessage = { 0 };
while(WM_QUIT != vMessage.message) {
while(PeekMessage(&vMessage, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&vMessage);
DispatchMessage(&vMessage);
}
if(WM_QUIT == vMessage.message) {
break;
}
#pragma region Render
float vClearColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
vD3dContext->ClearRenderTargetView(vRenderTargetView, vClearColor);
vSwapChain->Present(true, 0); // vsync
#pragma endregion
}
#pragma endregion
#pragma region Cleanup
if(vSwapChain) {
vSwapChain->SetFullscreenState(false, nullptr);
}
if(vD3dContext) {
vD3dContext->ClearState();
}
SAFE_RELEASE(vRenderTargetView);
SAFE_RELEASE(vBackBuffer);
SAFE_RELEASE(vSwapChain);
SAFE_RELEASE(vD3dContext);
SAFE_RELEASE(vD3dDevice);
SAFE_RELEASE(vDxgiFactory);
SAFE_RELEASE(vDxgiAdapter);
#ifdef _DEBUG
SAFE_RELEASE(vDebugger);
SAFE_RELEASE(vInfoQueue);
#endif
#pragma endregion
_getch();
return (int)vMessage.wParam;
}
Upvotes: 1
Reputation: 1
Check if your card support Quality=3 with CheckMultisampleQualityLevels. If it's just for lines I'd suggest try alpha anti aliasing D3D11_RASTERIZER_DESC.AntialiasedLineEnable
Upvotes: 0