DirectX 9 cannot change resolution - c++

I'm trying to change the window resolution like this:
pp.hDeviceWindow = hWnd;
pp.Windowed = true;
pp.BackBufferWidth = s.x;
pp.BackBufferHeight = s.y;
pp.BackBufferCount = 1;
pp.EnableAutoDepthStencil = true;
pp.AutoDepthStencilFormat = D3DFMT_D16;
pp.SwapEffect = D3DSWAPEFFECT_FLIP;
pp.BackBufferFormat = D3DFMT_R5G6B5;
m_pDevice->Reset(&pp);
Previously I resize window like this:
SetWindowPos(g_Window, HWND_TOPMOST, 0, 0, 521, 300, SWP_NOMOVE);
But reset always returns INVALID_CALL. What am I doing wrong?

This usually happens when you didn't dispose all you resources (vertex buffer, texture, ...)

Related

How to stop Direct3D 11 from stretching fullscreen to monitor size?

I am trying to make my Direct3D window fullscreen, with an 800x600 resolution. However, everything I try makes the screen stretch to cover the entire monitor, instead of just taking up an 800x600 area with black bars on the sides. The cursor is also stretched.
I create my swap chain with this DXGI_SWAP_CHAIN_DESC:
DXGI_SWAP_CHAIN_DESC sd{};
sd.BufferDesc.Width = 0;
sd.BufferDesc.Height = 0;
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 0;
sd.BufferDesc.RefreshRate.Denominator = 0;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
sd.OutputWindow = hWnd;
sd.Windowed = TRUE;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = 0;
Then I set the screen resolution using this code:
DEVMODEW devMode{};
devMode.dmSize = sizeof(devMode);
devMode.dmPelsWidth = width;
devMode.dmPelsHeight = height;
devMode.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
LONG res = ChangeDisplaySettingsW(&devMode, CDS_FULLSCREEN);
Finally I set the swap chain to be fullscreen:
HRESULT hr = swap->SetFullscreenState(on, nullptr);
Also, in my window procedure I call this whenever WM_SIZE is received:
swapChain.reset(); // Destroy swap chain
context->ClearState();
if (FAILED(swap->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0))) throw Exception("Failed to resize buffers");
swapChain.emplace(swap.Get(), device.Get(), context.Get(), hWnd); // Recreate swap chain
I have tried using DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH in both the DXGI_SWAP_CHAIN_DESC and the ResizeBuffers, as well as calling IDXGISwapChain::ResizeTarget with my desired size, but I still get the same problem.

Partially transparent window OpenGL/Win32

I have read every existing question on this tricky (niche) subject, but I am stuck. I have a Win32 window with an OpenGL context. I want my window to be partially transparent.
My result so far is that the entirety of the window is transparent. I want only the black area to be transparent, so that I can draw some 3D objects and they will look like they are coming of the window.
First, in my window class, I have set hbrBackground to black.
Windows::WindowClass windowClass;
windowClass.cbSize = sizeof(Windows::WindowClass);
windowClass.style = Windows::CS_VREDRAW | Windows::CS_HREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = moduleHandle;
windowClass.hIcon = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);
windowClass.hCursor = Windows::LoadCursor(0u, (X*)Windows::IDC_ARROW);
windowClass.hbrBackground = Windows::CreateSolidBrush(0x00000000);
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = (X*)name;
windowClass.hIconSm = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);
I have created my window with the WS_EX_LAYERED flag.
windowHandle = Windows::CreateWindow(Windows::WS_EX_LAYERED, (X*)name, "", Windows::WS_POPUP, w / 4, h / 4, w / 2, h / 2, 0u, 0u, moduleHandle, 0u);
In my pixel format, I have enabled alpha and composition.
PixelFormatDescriptor format;
format.nSize = sizeof(PixelFormatDescriptor);
format.nVersion = 1;
format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION;
format.iPixelType = PFD_TYPE_RGBA;
format.cColorBits = 32;
format.cRedBits = 0;
format.cRedShift = 0;
format.cGreenBits = 0;
format.cGreenShift = 0;
format.cBlueBits = 0;
format.cBlueShift = 0;
format.cAlphaBits = 8;
format.cAlphaShift = 0;
format.cAccumBits = 0;
format.cAccumRedBits = 0;
format.cAccumGreenBits = 0;
format.cAccumBlueBits = 0;
format.cAccumAlphaBits = 0;
format.cDepthBits = 24;
format.cStencilBits = 8;
format.cAuxBuffers = 0;
format.iLayerType = PFD_MAIN_PLANE;
format.bReserved = 0;
format.dwLayerMask = 0;
format.dwVisibleMask = 0;
format.dwDamageMask = 0;
I have tried the blur region "trick", but it has no effect. My result is not related to this piece of code.
struct DwmBlurBehind
{
U4 dwFlags;
S4 fEnable;
X* blurRegionHandle;
S4 fTransitionOnMaximized;
};
DwmBlurBehind blurBehind;
blurBehind.dwFlags = Windows::DWM_BB_ENABLE | Windows::DWM_BB_BLURREGION;
blurBehind.fEnable = true;
blurBehind.blurRegionHandle = Windows::CreateRectRgn(0, 0, -1, -1);
blurBehind.fTransitionOnMaximized = false;
Windows::DwmEnableBlurBehindWindow(windowHandle, &blurBehind);
Finally, I have set the LWA_COLORKEY and LWA_ALPHA attributes. This is what gave me the effect displayed. However, the color key does not seem to be taken into account (I have tried non-zero values as well).
Windows::SetLayeredWindowAttributes(windowHandle, 0, 170, Windows::LWA_COLORKEY | Windows::LWA_ALPHA);
I did not forget to enable blending.
GL::Enable(GL::BLEND);
GL::BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);
What you want to do requires window compositing which has been around since Windows Vista, so essentially every version of Windows you have to care about (Windows XP and earlier are at End of Life).
The key steps to take is, to enable DWM intra window compositing by enabling "Blur Behind Window" and use a WM_POPUP window; if you do not use WM_POPUP style the window manager will draw decorations and your OpenGL rendering will "hover" above that.
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = TRUE;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, &bb);
MARGINS margins = {-1};
impl_DwmExtendFrameIntoClientArea(hWnd, &margins);
Next, you must create an OpenGL context using the newer "attribute" API instead of using the pixelformat descriptor selection. With the attribute API you can select a transparent with alpha window format.
int attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, TRUE,
WGL_DOUBLE_BUFFER_ARB, TRUE,
WGL_SUPPORT_OPENGL_ARB, TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_TRANSPARENT_ARB, TRUE,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0
};
INT iPF;
UINT num_formats_choosen;
if( !wglChoosePixelFormatARB(
hDC,
attribs,
NULL,
1,
&iPF,
&num_formats_choosen) ) {
fprintf(stderr, "error choosing proper pixel format\n");
return NULL;
}
if( !num_formats_choosen ) {
return NULL;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
/* now this is a kludge; we need to pass something in the PIXELFORMATDESCRIPTOR
* to SetPixelFormat; it will be ignored, mostly. OTOH we want to send something
* sane, we're nice people after all - it doesn't hurt if this fails. */
DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);
if( !SetPixelFormat(hDC, iPF, &pfd) ) {
fprintf(stderr, "error setting proper pixel format\n");
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
return NULL;
}
I've got a complete working example for this in my wglarb wrapper repository over at GitHub:
https://github.com/datenwolf/wglarb/blob/master/test/layered.c
You might be missing the call to UpdateLayeredWindow . IIRC, not calling UpdateLayeredWindow results in some weird behavior. YMMV.
More details here
According with SetLayeredWindowAttributes doc you need to pass
a COLORREF structure that specifies the transparency color key to be
used when composing the layered window. All pixels painted by the
window in this color will be transparent. To generate a COLORREF, use
the RGB macro.
Review the second parameter of your call to this function.

IDXGISwapChain::ResizeBuffers triggers breakpoint when switching from fullscreen to windowed

Whenever my Direct3D 11 application switches from fullscreen to windowed mode, IDXGISwapChain::ResizeBuffers triggers a breakpoint. In Visual Studio's console, the message "Critical error 0xc0000374" is printed, with no other information. Apparently this means a heap corruption has occurred. Okay then. I can't get any more information about why this occurred because the window obnoxiously obscures my view and prevents me from controlling the visual studio window.
I'm following the suggestions made on this MSDN page. By that I mean I copied and pasted the code.
This is my setup code (ignore the lack of error checking):
DXGI_SWAP_CHAIN_DESC swap_chain_desc = { 0 };
swap_chain_desc.BufferCount = 2;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = window::get();
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swap_chain_desc.Windowed = TRUE;
swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
if (fullscreen == 1) {
swap_chain_desc.BufferDesc.Width = window::desktop_width();
swap_chain_desc.BufferDesc.Height = window::desktop_height();
} else {
swap_chain_desc.BufferDesc.Width = window::width();
swap_chain_desc.BufferDesc.Height = window::height();
}
HRESULT hr = D3D11CreateDeviceAndSwapChain (
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&swap_chain_desc,
&m_swap_chain,
&m_device,
NULL,
&m_context
);
ID3D11Texture2D* back_buffer;
hr = m_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer);
hr = m_device->CreateRenderTargetView(back_buffer, NULL, &m_view);
back_buffer->Release();
m_context->OMSetRenderTargets(1, &m_view, NULL);
D3D11_VIEWPORT viewport = { 0 };
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
if (fullscreen == 1) {
viewport.Width = window::desktop_width();
viewport.Height = window::desktop_height();
} else {
viewport.Width = window::width();
viewport.Height = window::height();
}
m_context->RSSetViewports(1, &viewport);
if (fullscreen == 1) {
m_swap_chain->SetFullscreenState(TRUE, NULL);
}
Is there anything there that might have caused this problem? The rendering code is just a ClearRenderTargetView and Present after a PeekMessage loop, nothing important.
This issue was fixed by showing the window before setting the swap chain's fullscreen state. Either call UpdateWindow(hwnd) and ShowWindow(hwnd, SW_SHOW) or set the window style to WS_VISIBLE when calling CreateWindow() or CreateWindowEx(), preferably before doing anything DirectX related.

Directx 11 Bitblt Alternative

I have the following function which I am trying to integrate into my directx 11 application. When I am using directx9 everything works fine but when converting to directx 11 I am getting a blue screen of death error at the Bitblt line (I must be doing something wrong with the HDC's?). I was wondering what the best way to convert this code to directx 11 compatible surfaces instead of HDC's would be.
Here is the function:
void CFlashDXPlayer::DrawFrame(HDC dc)
{
if (m_dirtyFlag)
{
IViewObject* pViewObject = NULL;
m_flashInterface->QueryInterface(IID_IViewObject, (LPVOID*) &pViewObject);
if (pViewObject != NULL)
{
// Combine regions
HRGN unionRgn, first, second = NULL;
unionRgn = CreateRectRgnIndirect(&m_dirtyRects[0]);
if (m_dirtyRects.size() >= 2)
second = CreateRectRgn(0, 0, 1, 1);
for (std::vector<RECT>::iterator it = m_dirtyRects.begin() + 1; it != m_dirtyRects.end(); ++it)
{
// Fill combined region
first = unionRgn;
SetRectRgn(second, it->left, it->top, it->right, it->bottom);
unionRgn = CreateRectRgn(0, 0, 1, 1);
CombineRgn(unionRgn, first, second, RGN_OR);
DeleteObject(first);
}
if (second)
DeleteObject(second);
RECT clipRgnRect; GetRgnBox(unionRgn, &clipRgnRect);
RECTL clipRect = { 0, 0, m_width, m_height };
// Fill background
if (m_transpMode != TMODE_FULL_ALPHA)
{
// Set clip region
SelectClipRgn(dc, unionRgn);
COLORREF fillColor = GetBackgroundColor();
HBRUSH fillColorBrush = CreateSolidBrush(fillColor);
FillRgn(dc, unionRgn, fillColorBrush);
DeleteObject(fillColorBrush);
// Draw to main buffer
HRESULT hr = pViewObject->Draw(DVASPECT_TRANSPARENT, 1, NULL, NULL, NULL, dc, &clipRect, &clipRect, NULL, 0);
assert(SUCCEEDED(hr));
}
else
{
if (m_alphaBlackDC == NULL)
{
// Create memory buffers
BITMAPINFOHEADER bih = {0};
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
bih.biPlanes = 1;
bih.biWidth = LONG(m_width);
bih.biHeight = -LONG(m_height);
m_alphaBlackDC = CreateCompatibleDC(dc);
m_alphaBlackBitmap = CreateDIBSection(m_alphaBlackDC, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&m_alphaBlackBuffer, 0, 0);
SelectObject(m_alphaBlackDC, m_alphaBlackBitmap);
m_alphaWhiteDC = CreateCompatibleDC(dc);
m_alphaWhiteBitmap = CreateDIBSection(m_alphaWhiteDC, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&m_alphaWhiteBuffer, 0, 0);
SelectObject(m_alphaWhiteDC, m_alphaWhiteBitmap);
}
HRESULT hr;
HBRUSH fillColorBrush;
// Render frame twice - against white and against black background to calculate alpha
SelectClipRgn(m_alphaBlackDC, unionRgn);
COLORREF blackColor = 0x00000000;
fillColorBrush = CreateSolidBrush(blackColor);
FillRgn(m_alphaBlackDC, unionRgn, fillColorBrush);
DeleteObject(fillColorBrush);
hr = pViewObject->Draw(DVASPECT_TRANSPARENT, 1, NULL, NULL, NULL, m_alphaBlackDC, &clipRect, &clipRect, NULL, 0);
assert(SUCCEEDED(hr));
// White background
SelectClipRgn(m_alphaWhiteDC, unionRgn);
COLORREF whiteColor = 0x00FFFFFF;
fillColorBrush = CreateSolidBrush(whiteColor);
FillRgn(m_alphaWhiteDC, unionRgn, fillColorBrush);
DeleteObject(fillColorBrush);
hr = pViewObject->Draw(DVASPECT_TRANSPARENT, 1, NULL, NULL, NULL, m_alphaWhiteDC, &clipRect, &clipRect, NULL, 0);
assert(SUCCEEDED(hr));
// Combine alpha
for (LONG y = clipRgnRect.top; y < clipRgnRect.bottom; ++y)
{
int offset = y * m_width * 4 + clipRgnRect.left * 4;
for (LONG x = clipRgnRect.left; x < clipRgnRect.right; ++x)
{
BYTE blackRed = m_alphaBlackBuffer[offset];
BYTE whiteRed = m_alphaWhiteBuffer[offset];
m_alphaBlackBuffer[offset + 3] = 255 - (whiteRed - blackRed);
offset += 4;
}
}
// Blit result to target DC
BitBlt(dc, clipRgnRect.left, clipRgnRect.top,
clipRgnRect.right - clipRgnRect.left,
clipRgnRect.bottom - clipRgnRect.top,
m_alphaBlackDC, clipRgnRect.left, clipRgnRect.top, SRCCOPY);
}
DeleteObject(unionRgn);
pViewObject->Release();
}
m_dirtyFlag = false;
m_dirtyRects.clear();
m_dirtyUnionRect.left = m_dirtyUnionRect.top = LONG_MAX;
m_dirtyUnionRect.right = m_dirtyUnionRect.bottom = -LONG_MAX;
}
}
The HDC I am passing to this function is created in the following manner:
D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory(&textureDesc, sizeof(textureDesc));
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
HRESULT hr = device->CreateTexture2D(&textureDesc, NULL, &m_flashTexture);
HRESULT hResult;
HDC hDC;
IDXGISurface1 *pSurface = NULL;
hResult = m_flashTexture->QueryInterface(__uuidof(IDXGISurface1), (void**)&pSurface);
hResult = pSurface->GetDC(TRUE, &hDC);
assert(SUCCEEDED(hResult));
m_flashPlayer->DrawFrame(hDC);
Any ideas of what I am doing wrong? I can't seem to figure out what is going on and why this is casuing a blue screen when if I use Directx 9 obejcts it doesn't. Is there a better way to do this?
(Also I've tried updating my drivers and they are all up to date).
Thank you for the help.
Turns out that this was indeed a driver issue. It works without a problem when I run with my graphics card set to the radeon in my latop, but when I have it on switchable for some reason it still crashes even though it should be selecting my radeon. I need to have the graphics mode fixed. Weird, but atleast its not my program I guess.
Can't really tell from code inspection. I haven't noticed anything blatantly wrong. There certainly should not be a any BSOD - that part is a driver bug. What hardware/driver are you running on?
A common reason for driver crashes though is illegally writing to some memory area, often if you're blitting to outside of your DC memory. I'd double check to verify that your regions are not out of bounds and that m_alphaBlackDC is the same size as dc.
I would also highly, highly recommend testing on another non-related GPU (that doesn't share the same hardware architecture).

D3D10CreateDeviceAndSwapChain() always failing with DXGI_ERROR_INVALID_CALL

I'm creating a hidden window and I'm looking to getting a pointer to IDXGISwapChain::Present(). The problem is that I can't get a valid Direct3D10 device, nor a valid swap chain.
HWND hwnd = CreateWindow(TEXT("flhiSTATIC"), TEXT("flh DXGI Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0, NULL, NULL, 0);
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(scd));
scd.BufferCount = 2;
RECT rcWnd;
GetClientRect(hwnd, &rcWnd);
scd.BufferDesc.Width = rcWnd.right - rcWnd.left;
scd.BufferDesc.Height = rcWnd.bottom - rcWnd.top;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // also tried DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scd.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
scd.BufferDesc.RefreshRate.Numerator = 60;
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hwnd;
scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 0;
scd.Windowed = TRUE;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
pD3D10CreateDeviceAndSwapChain = reinterpret_cast<D3D10CREATEDEVICEANDSWAPCHAIN_PROC *>(GetProcAddress(d3d10, "D3D10CreateDeviceAndSwapChain"));
HRESULT hr = pD3D10CreateDeviceAndSwapChain(NULL /*pAdapter*/, D3D10_DRIVER_TYPE_HARDWARE, NULL, D3D10_CREATE_DEVICE_DEBUG, D3D10_SDK_VERSION, &scd, &pSwapChain, &pDev);
// this guy always fails with 0 in both pSwapChain and pDev...
Any idea what might be wrong with the above code?
I completely forgot about the need to create or assign a pre-existing window class :(
That was the problem; lesson learned - always check the return codes of all the calls.
edit
I completely forgot to call CreateWindow with a valid window class, either one I'd previously registered or one that's registered by someone within the current module.