Got a LINK2019 error that I can't figure out. Error code: Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol __vsnprintf referenced in function "long __stdcall StringVPrintfWorkerA(char *,unsigned int,unsigned int *,char const *,char *)" (?StringVPrintfWorkerA##YGJPADIPAIPBD0#Z) Direct X C:\Visual Studio Programs\Direct X\Direct X\dxerr.lib(dxerra.obj) 1
main.cpp:
#include <Windows.h>
#include <memory>
#include "BlankDemo.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
LPWSTR cmdLine, int cmdShow)
{
UNREFERENCED_PARAMETER(prevInstance);
UNREFERENCED_PARAMETER(cmdLine);
WNDCLASSEX wndClass = { 0 };
wndClass.cbSize = sizeof(WNDCLASS);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hInstance;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = "DX11BookWindowClass";
if (!RegisterClassEx(&wndClass))
return -1;
RECT rc = { 0, 0, 640, 480 };
AdjustWindowRect(&rc, WS_EX_OVERLAPPEDWINDOW, FALSE);
HWND hwnd = CreateWindowA("DX11BookWindowClass", "BlankWin32Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left,
rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
if (!hwnd)
return -1;
ShowWindow(hwnd, cmdShow);
std::auto_ptr<Dx11DemoBase> demo(new BlankDemo());
// Demo Initialize
bool result = demo->Initialize(hInstance, hwnd);
// Error reporting if there is an issue
if (result == false)
return -1;
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Update and Draw
demo->Update(0.0f);
demo->Render();
}
}
// Demo Shutdown
demo->Shutdown();
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT paintStruct;
HDC hDC;
switch (message)
{
case WM_PAINT:
hDC = BeginPaint(hwnd, &paintStruct);
EndPaint(hwnd, &paintStruct);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
defualt:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
// implementation of the BlankDemo class
BlankDemo::BlankDemo()
{
}
BlankDemo::~BlankDemo()
{
}
bool BlankDemo::LoadContent()
{
return true;
}
void BlankDemo::UnloadContent()
{
}
void BlankDemo::Update(float dt)
{
}
void BlankDemo::Render()
{
if (d3dContext_ == 0)
return;
float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);
swapChain_->Present(0, 0);
}
BlankDemo.h file:
#pragma once
#ifndef _BLANK_DEMO_H_
#define _BLANK_DEMO_H_
#include "Dx11DemoBase.h"
class BlankDemo : public Dx11DemoBase
{
public:
BlankDemo();
virtual ~BlankDemo();
bool LoadContent();
void UnloadContent();
void Update(float dt);
void Render();
};
#endif // !_BLANK_DEMO_H_
Dx11DemoBase::Dx11DemoBase() : driverType_(D3D_DRIVER_TYPE_NULL),
featureLevel_(D3D_FEATURE_LEVEL_11_0), d3dDevice_(0), d3dContext_(0),
swapChain_(0), backBufferTarget_(0)
{
}
Dx11DemoBase::~Dx11DemoBase()
{
Shutdown();
}
bool Dx11DemoBase::LoadContent()
{
// Override with demo specifics, if any...
return true;
}
void Dx11DemoBase::UnloadContent()
{
// Override with demo specifics, if any...
}
void Dx11DemoBase::Shutdown()
{
UnloadContent();
if (backBufferTarget_) backBufferTarget_->Release();
if (swapChain_) swapChain_->Release();
if (d3dContext_) d3dContext_->Release();
if (d3dDevice_) d3dDevice_->Release();
d3dDevice_ = 0;
d3dContext_ = 0;
swapChain_ = 0;
backBufferTarget_ = 0;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
bool Dx11DemoBase::Initialize(HINSTANCE hInstance, HWND hwnd)
{
hInstance_ = hInstance;
hwnd_ = hwnd;
RECT dimensions;
GetClientRect(hwnd, &dimensions);
unsigned int width = dimensions.right - dimensions.left;
unsigned int height = dimensions.bottom - dimensions.top;
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int totalDriverTypes = ARRAYSIZE(driverTypes);
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
unsigned int totalFeatureLevels = ARRAYSIZE(featureLevels);
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = true;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
unsigned int creationFlags = 0;
#ifdef _DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT result;
unsigned int driver = 0;
for (driver = 0; driver < totalDriverTypes; ++driver)
{
result = D3D11CreateDeviceAndSwapChain(0, driverTypes[driver], 0,
creationFlags, featureLevels, totalFeatureLevels, D3D11_SDK_VERSION,
&swapChainDesc, &swapChain_, &d3dDevice_, &featureLevel_, &d3dContext_);
if (SUCCEEDED(result))
{
driverType_ = driverTypes[driver];
break;
}
}
if (FAILED(result))
{
DXTRACE_MSG("Failed to create the Direct3d device!");
return false;
}
ID3D11Texture2D* backBufferTexture;
result = swapChain_->GetBuffer(0, _uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTexture);
if (FAILED(result))
{
DXTRACE_MSG("Failed to get the swap chain back buffer!");
return false;
}
result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0, &backBufferTarget_);
if (backBufferTexture)
backBufferTexture->Release();
if (FAILED(result))
{
DXTRACE_MSG("Failed to create the render target view!");
return false;
}
d3dContext_->OMSetRenderTargets(1, &backBufferTarget_, 0);
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(width);
viewport.Height = static_cast<float>(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
d3dContext_->RSSetViewports(1, &viewport);
return LoadContent();
}
And lastly, the Dx11DemoBase.h header:
#pragma once
#ifndef _DEMO_BASE_H_
#define _DEMO_BASE_H_
#include <d3d11.h>
#include <D3DX11.h>
#include <dxerr.h>
class Dx11DemoBase
{
public:
Dx11DemoBase();
virtual ~Dx11DemoBase();
bool Initialize(HINSTANCE hInstance, HWND hwnd);
void Shutdown();
virtual bool LoadContent();
virtual void UnloadContent();
virtual void Update(float dt) = 0;
virtual void Render() = 0;
protected:
HINSTANCE hInstance_;
HWND hwnd_;
D3D_DRIVER_TYPE driverType_;
D3D_FEATURE_LEVEL featureLevel_;
ID3D11Device* d3dDevice_;
ID3D11DeviceContext* d3dContext_;
IDXGISwapChain* swapChain_;
ID3D11RenderTargetView* backBufferTarget_;
};
#endif // !_DEMO_BASE_H_
Add legacy_stdio_definitions.lib to Additional dependencies list in the Project properties > Configuration Properties > Linker > Input as recommended in this answer: https://stackoverflow.com/a/34230122/6693304
The legacy DirectX SDK is deprecated, so it hasn't been officially updated since the release of Visual Studio 2010 RTM (June 2010). See Microsoft Docs
This has a few specific implications:
The Windows 8.0 SDK, Windows 8.1 SDK, and Windows 10 SDK all have newer headers than the legacy DirectX SDK where they overlap. You can still make use of it with VS 2012, 2013, 2015, or 2017 but you need to reverse the traditional include/lib path order in the VC++ Directories settings. There are a few other quirks covered at the bottom of this Microsoft Docs topic page. See also The Zombie DirectX SDK.
The DLL import libraries in the legacy DirectX SDK are missing some of the imports that are present in the Windows 8.x or Windows 10 SDK. They generally work fine with all C/C++ compilers because they are fairly standard Win32 without any version-specific CRT references.
Static libraries, however, are not guaranteed to be binary compatible from version to version of the C/C++ compiler. dxguid.lib just has some data in it, so it generally works, but dxerr.lib has actual code. Hence with the major changes in the C/C++ Runtime in VS 2015, it no longer works without link errors.
There are two basic solutions to the dxerr.lib problem:
Build your own copy of the code. It's available here. This is the most robust as it will always match your compiler toolset.
You can add legacy_stdio_definitions.lib, but keep in mind that you are already relying on very out-dated files so you should work to remove/minimize use of the legacy DirectX SDK over time.
Many online tutorials for DirectX 11 and books are outdated w.r.t. to the DirectX SDK and still use d3dx11 which is also deprecated. There are numerous open source replacements available for this functionality. See Living without D3DX.
All that said, this question has already been answered on StackOverflow and would have shown up if you just searched dxerr.
Related
Currently I wrote some code that loads original image with WIC, stores it in variable as ID2D1Bitmap* and then creates another resized one, via compatible render target and scale effect (I can provide example, if needed), so, for every basic image I have two bitmaps.
However, bitmaps use a lot of ram — loading just 10 2mb images costs more than 100mb of ram. I don’t understand why it uses ram at all, if it should be in GPU memory, as I understand.
So, I asking here the solution to reduce that ram usage.
I read about atlas method, but it seems to be hard to develop. Maybe there are another tricks?
Example of code
#include <Windows.h>
HDC hdcDevice = GetDC(NULL);
int xw = GetDeviceCaps(hdcDevice, HORZRES);
int yw = GetDeviceCaps(hdcDevice, VERTRES);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
#include <d2d1_1.h>
#include <dwrite.h>
#include <wincodec.h>
#pragma comment(lib, "d2d1")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dwrite.lib")
using namespace std;
template<class Interface>
inline void SafeRelease(
Interface** ppInterfaceToRelease)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
ID2D1Bitmap* bitmap;
ID2D1Factory* factory;
IWICImagingFactory* d2dWICFactory;
IWICFormatConverter* d2dConverter;
IDWriteFactory* writeFactory;
IWICFormatConverter* d2dConverter2 = nullptr;
ID2D1BitmapRenderTarget* back = nullptr;
ID2D1DeviceContext* tar = nullptr;
ID2D1DeviceContext* target = nullptr;
ID2D1Effect* scale = nullptr;
class UIElement
{
public:
ID2D1Bitmap* imgOrig;
ID2D1Bitmap* img;
D2D1_SIZE_F si;
ID2D1DeviceContext* tar;
float x;
float y;
float width;
float height;
UIElement(ID2D1DeviceContext *tar, float x, float y, float width, float height)
{
this->tar = tar;
this->x = x; this->y = y; this->width = width; this->height = height;
this->img = nullptr;
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
}
void setBackgroundImage(const wchar_t* path)
{
IWICBitmapDecoder* d2dDecoder;
IWICBitmapFrameDecode* d2dBmpSrc;
IWICFormatConverter* d2dConverter2 = nullptr;
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
d2dWICFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, &d2dDecoder);
if (d2dDecoder)
{
d2dDecoder->GetFrame(0, &d2dBmpSrc);
if (d2dBmpSrc && d2dConverter2)
{
d2dConverter2->Initialize(d2dBmpSrc, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
tar->CreateBitmapFromWicBitmap(d2dConverter2, NULL, &imgOrig);
if (imgOrig)
{
si = imgOrig->GetSize();
RescaleImage();
}
}
}
SafeRelease(&d2dConverter2);
SafeRelease(&d2dDecoder);
SafeRelease(&d2dBmpSrc);
}
inline void RescaleImage(ID2D1Bitmap* cache = nullptr)
{
SafeRelease(&img);
tar->CreateBitmap(D2D1::SizeU(width, height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &img);
if (cache != nullptr)
scale->SetInput(0, cache);
else if (this->imgOrig)
scale->SetInput(0, this->imgOrig);
scale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(this->width / si.width, this->height / si.height));
ID2D1BitmapRenderTarget* rnd = nullptr;
tar->CreateCompatibleRenderTarget(D2D1::SizeF(width, height), &rnd);
ID2D1DeviceContext* rndc = nullptr;
rnd->QueryInterface(&rndc);
rndc->BeginDraw();
rndc->DrawImage(scale);
rndc->EndDraw();
img->CopyFromRenderTarget(0, rndc, 0);
SafeRelease(&rndc);
SafeRelease(&rnd);
}
inline void Render()
{
D2D1_RECT_F rect = D2D1::RectF(this->x, this->y, this->x + this->width, this->y + this->height);
if(img)
this->tar->DrawBitmap(img, rect);
}
}*elements[100] = { NULL };
inline void Render()
{
tar->BeginDraw();
tar->Clear(D2D1::ColorF(1,1,1,1));
target->BeginDraw();
target->Clear(D2D1::ColorF(1,0,1,1));
for (int i = 0; i < 100 && elements[i]; i++)
elements[i]->Render();
auto hr = target->EndDraw();
tar->DrawImage(bitmap);
hr = tar->EndDraw();
}
int WINAPI WinMain(HINSTANCE hin, HINSTANCE, LPSTR, int)
{
ReleaseDC(NULL, hdcDevice);
WNDCLASS c = { NULL };
c.lpszClassName = L"asd";
c.lpfnWndProc = WndProc;
c.hInstance = hin;
c.style = CS_VREDRAW | CS_HREDRAW;
c.hCursor = LoadCursor(NULL, IDC_ARROW);
c.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
RegisterClass(&c);
int cx = 500, cy = 500;
int x = xw / 2 - cx / 2, y = yw / 2 - cy / 2;
HWND hwnd = CreateWindowEx(NULL, L"asd", L"asd", WS_POPUP | WS_VISIBLE, x, y, cx, cy, NULL, NULL, hin, 0);
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
CoInitialize(NULL);
D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_MULTI_THREADED, &factory);
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory), (void**)(&d2dWICFactory));
d2dWICFactory->CreateFormatConverter(&d2dConverter);
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(writeFactory),
reinterpret_cast<IUnknown**>(&writeFactory)
);
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
D2D1_SIZE_U size = D2D1::SizeU(cx, cy);
ID2D1HwndRenderTarget* a = nullptr;
factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)), D2D1::HwndRenderTargetProperties(hwnd, size), &a);//);
a->QueryInterface(&tar);
tar->CreateCompatibleRenderTarget(&back);
back->QueryInterface(&target);
back->GetBitmap(&bitmap);
target->CreateEffect(CLSID_D2D1Scale, &scale);
scale->SetValue(D2D1_SCALE_PROP_INTERPOLATION_MODE, D2D1_INTERPOLATION_MODE::D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
MSG msg;
for (int i = 0; i < 10; i++)
{
elements[i] = new UIElement(target, 50*i, 10, 50, 50);
elements[i]->setBackgroundImage(L"bitmap.bmp");
}
while (GetMessage(&msg, NULL, 0, 0))
{
Render();
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
switch (message)
{
case WM_LBUTTONDOWN:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wp, lp);
}
return NULL;
}
*I want Windows 7 support.
As Simon Mourier pointed in comments, it seems that in my code WIC bitmap's memory, allocated at RAM is not being free, even despite on realizing all wic's com objects.
So, I tried to get bitmap from wic not to final direct2d bitmap I need but for temporary direct2d bitmap, then create empty final direct2d bitmap, copy there temp bitmap and release temp bitmap.
This worked, now with 10 2mb png images (with their resized duplicates) my program uses few megabytes of RAM, and earlier about 120mb.
// WIC loading stuff
ID2D1Bitmap *temp = nullptr;
ID2D1Bitmap *imgOrig = nullptr;
target->CreateBitmapFromWicBitmap(d2dConverter, NULL, &temp);
if (temp)
{
D2D1_SIZE_F size = temp->GetSize();
target->CreateBitmap(D2D1::SizeU(size.width, size.height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &imgOrig);
imgOrig->CopyFromBitmap(0, temp, 0);
SafeRelease(&temp);
}
// Release WIC
Why is D3Dcompiler_43.dll Loaded and Unloaded every frame?
Why does my two window direct-X 11 application drop from 2000 Hz to 12 Hz when I resize one of the windows?
In simplified sample I have attached code from, it starts with two identical sized windows at 2000 Hz, but if I change the size of either one, the frame rate of both goes to 12 Hz.
If I minimize either one, I get back to full speed, 4000Hz with one window.
When it is running at 12 Hz, I get the following Output Trace EVERY FRAME:
'Galaxies.exe' (Win32): Loaded 'C:\Windows\System32\D3Dcompiler_43.dll'
'Galaxies.exe' (Win32): Unloaded 'C:\Windows\System32\D3Dcompiler_43.dll'
This trace comes out when I call IDGXISwapChain->Present().
This trace does not come out when running 2000Hz.
I do not expect to need D3Dcompiler_43.dll at all, since I build my shaders at compile time, not run time. But if it did need it, then it should load it and keep it, not load each frame.
And if I make the window sizes match again, or minimize one, then the trace stops.
C++, Directx 11
My basic template is based on the Microsoft Sample "SimpleTexturePC".
Main changes from that template:
compile textures into program rather than reading at run time
compile shaders into program rather than reading at run time
extend DeviceResources to be able to support more than one window
by making arrays for all the resources, such as RenderTargetView
Extending Main.cpp to create more than one window, and have a WinProc for each.
Each of these unique WinProcs then calls a WinProcCommon with an "index" that identifies the window.
Adding a second camera for use on 2nd window
Adding a trace to the main application "Galaxies.cpp" so I could see the FPS.
(the rest of the main application behavior is not in simplified sample).
Main.cpp
//
// Main.cpp
//
#include ...
namespace
{
std::unique_ptr<Galaxies> g_game_p;
};
LPCWSTR g_szAppName0 = L"World1";
LPCWSTR g_szAppName1 = L"World2";
LPCWSTR g_szAppName2 = L"World3";
LRESULT CALLBACK WndProcWorld1(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld2(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcWorld3(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcCommon(UINT, HWND, UINT, WPARAM, LPARAM);
// Entry point
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
if (!XMVerifyCPUSupport())
return 1;
HRESULT hr = CoInitializeEx(nullptr, COINITBASE_MULTITHREADED);
if (FAILED(hr))
return 1;
g_game_p = std::make_unique<Galaxies>();
int border = getInvisableBorderWidth();
// Register / create window 1
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld1;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON1");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass1";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON1");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName0, WS_OVERLAPPEDWINDOW,
50 - border, 50, w, h, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow1, hwnd, w, h); // this chooses non-fullscreen location, though we will go full screen in a sec...
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Register / create window 2
{
// Register class
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProcWorld2;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIconW(hInstance, L"IDI_ICON2");
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = L"WindowClass2";
wcex.hIconSm = LoadIconW(wcex.hInstance, L"IDI_ICON2");
if (!RegisterClassExW(&wcex)) // W implies unicode version.
return 1;
// Create window
int w, h;
g_game_p->GetDefaultWindowSize(w, h);
HWND hwnd = CreateWindowExW(0, wcex.lpszClassName, g_szAppName1, WS_OVERLAPPEDWINDOW,
100 - border, 100, w + 00, h + 00, nullptr, nullptr, hInstance, nullptr);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(g_game_p.get()));
if (!hwnd)
return 1;
g_game_p->Initialize(kGameWindow2, hwnd, w, h);
ShowWindow(hwnd, SW_SHOWNORMAL);
}
// Main message loop
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_game_p->Tick();
}
}
g_game_p.reset();
CoUninitialize();
return static_cast<int>(msg.wParam);
}
// First parameter "index" used to differentiate the three windows.
LRESULT CALLBACK WndProcCommon(UINT index, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WindowStruct& winInfo = g_deviceResources_p->GetWindowStruct(index);
auto galaxies_p = reinterpret_cast<Galaxies*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
switch (message)
{
case WM_PAINT:
if (winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
galaxies_p->Tick();
}
else
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
break;
case WM_MOVE:
if (galaxies_p)
{
galaxies_p->OnWindowMoved(index);
}
break;
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
{
if (!winInfo.minimized)
{
winInfo.minimized = true;
if (!winInfo.in_suspend && galaxies_p)
galaxies_p->OnSuspending();
winInfo.in_suspend = true;
}
}
else if (winInfo.minimized)
{
winInfo.minimized = false;
if (winInfo.in_suspend && galaxies_p)
galaxies_p->OnResuming();
winInfo.in_suspend = false;
}
else if (!winInfo.in_sizemove && galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_ENTERSIZEMOVE:
winInfo.in_sizemove = true;
break;
case WM_EXITSIZEMOVE:
winInfo.in_sizemove = false;
if (galaxies_p)
{
RECT rc;
GetWindowRect(hWnd, &rc);
galaxies_p->OnWindowSizeChanged(index, rc.right - rc.left, rc.bottom - rc.top);
}
break;
case WM_GETMINMAXINFO:
if (lParam)
{
auto info = reinterpret_cast<MINMAXINFO*>(lParam);
info->ptMinTrackSize.x = 320;
info->ptMinTrackSize.y = 200;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case ... mouse cases
Mouse::ProcessMessage(message, wParam, lParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
Keyboard::ProcessMessage(message, wParam, lParam);
break;
case WM_MENUCHAR:
return MAKELRESULT(0, MNC_CLOSE);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Windows procedure x3
LRESULT CALLBACK WndProcWorld1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow1, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow2, hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProcWorld3(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return WndProcCommon(kGameWindow3, hWnd, message, wParam, lParam);
}
// Exit helper
void ExitGame() noexcept
{
PostQuitMessage(0);
}
Galaxies.cpp
//
// Galaxies.cpp
//
#include ...
// Global variables
std::unique_ptr<DX::StepTimer> g_timer_p;
std::unique_ptr<DX::DeviceResources> g_deviceResources_p;
std::unique_ptr<DirectX::CommonStates> g_states_p;
std::unique_ptr<padInput> g_input_p;
std::unique_ptr<Camera> g_camera_p[2];
std::unique_ptr<HudText> g_text_p;
Galaxies::Galaxies() noexcept(false)
{
g_deviceResources_p = std::make_unique<DX::DeviceResources>(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
g_deviceResources_p->RegisterDeviceNotify(this);
}
void Galaxies::Initialize(UINT index, HWND window, int width, int height)
{
static int once = true;
if (once)
{
g_deviceResources_p->CreateDeviceResources();
once = false;
}
switch (index)
{
case kGameWindow1:
{
g_timer_p = std::make_unique<DX::StepTimer>();
g_input_p = std::make_unique<padInput>();
g_camera_p[0] = std::make_unique<Camera>();
g_camera_p[1] = std::make_unique<Camera>();
g_text_p = std::make_unique<HudText>();
// PER OBJECT INITIALIZE
g_camera_p[0]->Initialize(0);
g_camera_p[1]->Initialize(1);
g_input_p ->Initialize();
g_text_p ->Initialize();
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
OnDeviceRestored();
break;
}
case kGameWindow2:
case kGameWindow3:
default:
{
g_deviceResources_p->SetWindow(index, window, width, height);
g_deviceResources_p->CreateWindowSizeDependentResources(index);
break;
}
}
}
void Galaxies::GetDefaultWindowSize(int& width, int& height) const noexcept
{
...
}
void Galaxies::OnDeviceLost()
{
g_states_p.reset();
m_spPerFrameConstantBuffer.Reset();
g_text_p->OnDeviceLost();
}
void Galaxies::OnDeviceRestored()
{
CreateDeviceDependentResources();
CreateWindowSizeDependentResources(0);
CreateWindowSizeDependentResources(1);
WindowSizeChangeConfirmed(0);
WindowSizeChangeConfirmed(1);
g_text_p->OnDeviceRestored();
}
void Galaxies::OnSuspending()
{
}
void Galaxies::OnResuming()
{
g_timer_p->ResetElapsedTime();
}
void Galaxies::OnWindowMoved(UINT index)
{
auto r = g_deviceResources_p->GetOutputSize(index);
g_deviceResources_p->WindowSizeChanged(index, r.width, r.height);
}
// Pass in CURRENT (Last known) window size (icluding frame), so we can compare that with current size
// as read in deviceResources.
void Galaxies::OnWindowSizeChanged(UINT index, int width, int height)
{
// returns false if size unchanged
if (g_deviceResources_p->WindowSizeChanged(index, width, height))
{
CreateWindowSizeDependentResources(0);
WindowSizeChangeConfirmed(index);
}
}
void Galaxies::Tick()
{
UpdateRenderGPUTextures();
g_timer_p->Tick([&]()
{
UpdateInput();
UpdateCameras();
UpdateWorld();
});
RenderWorld(0);
if (!g_deviceResources_p->isWindowMinimized(1))
{
RenderWorld(1);
}
}
void Galaxies::Clear(int index)
{
// Clear the views.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->ClearRenderTargetView(renderTargetView, Colors::Black);
context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
}
void Galaxies::CreateDeviceDependentResources()
{
auto device = g_deviceResources_p->GetD3DDevice();
g_states_p = std::make_unique<CommonStates>(device);
// Create constant buffers.
D3D11_BUFFER_DESC bufferDesc = {};
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.ByteWidth = sizeof(PerFrameConstantBuffer);
DX::ThrowIfFailed(device->CreateBuffer(&bufferDesc, nullptr, m_spPerFrameConstantBuffer.ReleaseAndGetAddressOf()));
}
// Allocate all memory resources that change on a window SizeChanged event.
void Galaxies::CreateWindowSizeDependentResources(UINT index)
{
// TODO: Initialize windows-size dependent objects here.
}
void Galaxies::UpdateRenderGPUTextures()
{
// Don't try to render anything before the first Update.
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
}
void Galaxies::UpdateInput()
{
g_input_p->Update();
if (g_input_p->isKeyDownEdge(escape))
{
ExitGame();
}
}
void Galaxies::UpdateCameras()
{
g_camera_p[0]->Update();
// g_camera_p[1]->Update();
}
// Updates the world.
void Galaxies::UpdateWorld()
{
}
void Galaxies::RenderWorld(int index) // index 0, 1. not 2 (not edit window)
{
if (g_timer_p->GetFrameCount() == 0)
{
return;
}
Clear(index);
// Update Constants Buffer with per-frame variables.
// Though I now do this up to 3 times per frame - once per window.
auto context = g_deviceResources_p->GetD3DDeviceContext();
auto d3dBuffer = m_spPerFrameConstantBuffer.Get();
// Exclude 3rd window for now
if (index != 2)
{ // PRE-LOCK
MapGuard mappedResource(context, d3dBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0);
PerFrameConstantBuffer* data = reinterpret_cast<PerFrameConstantBuffer*>(mappedResource.get());
g_camera_p[index]->GetPerFrameData(data);
data->frameTime = g_timer_p->GetElapsedSeconds();
if (g_input_p->isButtonToggleSet(leftShoulder))
{
data->frameTime *= 5;
}
data->totalTime = g_timer_p->GetTotalSeconds();
int fps = (int)g_timer_p->GetFramesPerSecond();
char buffer[TEXT_NUM_OF_CHAR];
memset(buffer, 127, sizeof(buffer));
if (index == 0)
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 1 ");
}
else
{
snprintf(&buffer[0 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Window 2 ");
}
snprintf(&buffer[TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, "Galaxies V0.01 ");
snprintf(&buffer[2 * TEXT_NUM_CHAR_PER_ROW], TEXT_NUM_CHAR_PER_ROW + 1, " FPS = %d ", fps);
for (int i = 0; i < TEXT_NUM_OF_CHAR; i++)
{
data->alpha[4 * i] = buffer[i] - 0x20; // 0x20 is the first ascii char in our texture atlas. It is " "
}
} // UNLOCK (in mappedResource destructor)
context->VSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
context->PSSetConstantBuffers(CONSTANTS_PER_FRAME, 1, &d3dBuffer);
auto renderTargetView = g_deviceResources_p->GetRenderTargetView(index);
auto depthStencilView = g_deviceResources_p->GetDepthStencilView(index);
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
// Set the viewport.
auto viewport = g_deviceResources_p->GetScreenViewport(index);
context->RSSetViewports(1, &viewport);
if (index != 2)
{
g_text_p->Render();
}
g_deviceResources_p->Present(index);
}
void Galaxies::WindowSizeChangeConfirmed(UINT index)
{
auto size = g_deviceResources_p->GetOutputSize(index);
switch (index)
{
case (kGameWindow1):
g_camera_p[0]->OnWindowSizeChanged(size.width, size.height);
g_text_p ->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow2):
g_camera_p[1]->OnWindowSizeChanged(size.width, size.height);
break;
case (kGameWindow3):
break;
default:
break;
}
}
DeviceResources.cpp
//
// DeviceResources.cpp
//
#include ...
using namespace DirectX;
using namespace DX;
using Microsoft::WRL::ComPtr;
DeviceResources::DeviceResources(
DXGI_FORMAT backBufferFormat,
DXGI_FORMAT depthBufferFormat,
UINT backBufferCount,
D3D_FEATURE_LEVEL minFeatureLevel,
unsigned int flags) noexcept :
m_backBufferFormat{ backBufferFormat },
m_depthBufferFormat{ depthBufferFormat },
m_backBufferCount{backBufferCount},
m_d3dMinFeatureLevel(minFeatureLevel),
m_window(),
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
m_colorSpace(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709),
m_options(flags | c_FlipPresent | c_AllowTearing),
m_deviceNotify(nullptr)
{
m_windowCount = 0;
for (int index = 0; index < c_MaxWindows; index++)
{
m_window[index] = nullptr;
m_WindowStruct[index] = WindowStruct();
m_screenViewport[index] = { 100, 100, 800, 600, 0, 1 };
}
}
void DeviceResources::CreateDeviceResources()
{
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
CreateFactory();
...
// Determine feature levels
...
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
// Create the Direct3D 11 API device / context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
HRESULT hr = E_FAIL;
if (adapter)
{
hr = D3D11CreateDevice(
adapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
nullptr,
creationFlags,
s_featureLevels,
featLevelCount,
D3D11_SDK_VERSION,
device.GetAddressOf(),
&m_d3dFeatureLevel,
context.GetAddressOf()
);
}
if (FAILED(hr))
{
// fall back to WARP device.
...
}
ThrowIfFailed(hr);
ThrowIfFailed(device.As(&m_d3dDevice));
ThrowIfFailed(context.As(&m_d3dContext));
}
// recreate every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources(UINT index)
{
if (!m_window[index])
{
throw std::exception("need valid window handle");
}
// Clear the previous window size specific context.
ID3D11RenderTargetView* nullViews[] = { nullptr };
m_d3dContext->OMSetRenderTargets(_countof(nullViews), nullViews, nullptr);
m_d3dRenderTargetView[index].Reset();
m_d3dDepthStencilView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_d3dContext->Flush();
// Determine the render target size in pixels.
const UINT backBufferWidth = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.width), 1u);
const UINT backBufferHeight = std::max<UINT>(static_cast<UINT>(m_WindowStruct[index].currentPos.height), 1u);
const DXGI_FORMAT backBufferFormat = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? NoSRGB(m_backBufferFormat) : m_backBufferFormat;
if (m_swapChain[index])
{
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain[index]->ResizeBuffers(
m_backBufferCount,
backBufferWidth,
backBufferHeight,
backBufferFormat,
(m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
...
}
else
{
ThrowIfFailed(hr);
}
}
else
{
// Create a descriptor for the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = backBufferWidth;
swapChainDesc.Height = backBufferHeight;
swapChainDesc.Format = backBufferFormat;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = m_backBufferCount;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = (m_options & (c_FlipPresent | c_AllowTearing | c_EnableHDR)) ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc.Flags = (m_options & c_AllowTearing) ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fsSwapChainDesc = {};
fsSwapChainDesc.Windowed = TRUE;
// Create a SwapChain
ThrowIfFailed(m_dxgiFactory->CreateSwapChainForHwnd(
m_d3dDevice.Get(),
m_window[index],
&swapChainDesc,
&fsSwapChainDesc,
nullptr, m_swapChain[index].ReleaseAndGetAddressOf()
));
ThrowIfFailed(m_dxgiFactory->MakeWindowAssociation(m_window[index], DXGI_MWA_NO_ALT_ENTER));
}
// Create a render target view of the swap chain back buffer.
ThrowIfFailed(m_swapChain[index]->GetBuffer(0, IID_PPV_ARGS(m_renderTargetTexture[index].ReleaseAndGetAddressOf())));
CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2D, m_backBufferFormat);
ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(
m_renderTargetTexture[index].Get(),
&renderTargetViewDesc,
m_d3dRenderTargetView[index].ReleaseAndGetAddressOf()
));
if (m_depthBufferFormat != DXGI_FORMAT_UNKNOWN)
{
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
m_depthBufferFormat,
backBufferWidth,
backBufferHeight,
1,
1,
D3D11_BIND_DEPTH_STENCIL
);
ThrowIfFailed(m_d3dDevice->CreateTexture2D(
&depthStencilDesc,
nullptr,
m_depthStencilTexture[index].ReleaseAndGetAddressOf()
));
CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(
m_depthStencilTexture[index].Get(),
&depthStencilViewDesc,
m_d3dDepthStencilView[index].ReleaseAndGetAddressOf()
));
}
// Set the 3D rendering viewport
m_screenViewport[index] = CD3D11_VIEWPORT(
0.0f,
0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
}
void DeviceResources::SetWindow(UINT index, HWND window, int width, int height) noexcept
{
m_window[index] = window;
int indent = 50 * (index + 1);
RECTxywh windowPos = { indent - getInvisableBorderWidth(), indent, width, height };
m_WindowStruct[index].setWindowedByWindowPos(windowPos, 0, true);
}
bool DeviceResources::WindowSizeChanged(UINT index, int width, int height)
{
RECTxywh newRc = { 0, 0, width, height };
RECTxywh oldRc = { 0, 0, m_WindowStruct[index].currentPos.width, m_WindowStruct[index].currentPos.height };
if (newRc == oldRc)
{
// i.e. size didnt actually change
return false;
}
m_WindowStruct[index].setWindowedByWindowPos(newRc, 0, false);
CreateWindowSizeDependentResources(index);
return true;
}
// Recreate all device resources
void DeviceResources::HandleDeviceLost(UINT index)
{
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceLost();
}
m_d3dDepthStencilView[index].Reset();
m_d3dRenderTargetView[index].Reset();
m_renderTargetTexture[index].Reset();
m_depthStencilTexture[index].Reset();
m_swapChain[index].Reset();
m_d3dContext.Reset();
m_d3dDevice.Reset();
m_dxgiFactory.Reset();
CreateDeviceResources();
CreateWindowSizeDependentResources(index);
if (m_deviceNotify)
{
m_deviceNotify->OnDeviceRestored();
}
}
int DeviceResources::getNumberOfMonitors()
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
IDXGIOutput* output = NULL;
int count = 0;
for (int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
count++;
}
return count;
}
RECTxywh DeviceResources::getMonitorSize(int monitor)
{
RECT position = getMonitorPos(monitor);
RECTxywh size(0, 0, position.right - position.left, position.bottom - position.top);
return size;
}
// 1 based index into monitors
RECT DeviceResources::getMonitorPos(int monitor)
{
ComPtr<IDXGIAdapter1> adapter;
GetHardwareAdapter(adapter.GetAddressOf());
RECT pos = {};
IDXGIOutput* output = NULL;
int count = -1;
if ( DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(monitor, &output) )
{
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc(&outputDesc);
pos = outputDesc.DesktopCoordinates;
}
return pos;
}
RECT DeviceResources::getWindowPos(int index)
{
RECT windowRect;
HWND window = m_window[index];
GetWindowRect(window, &windowRect);
return windowRect;
}
void DeviceResources::setWindowPosition(int index, RECTxywh pos)
{
HWND hWnd = m_window[index];
SetWindowPos(hWnd, HWND_TOP, pos.left, pos.top, pos.width, pos.height, SWP_FRAMECHANGED)
ShowWindow(hWnd, SW_SHOWNORMAL)
}
bool DeviceResources::isWindowMinimized(int index)
{
return IsIconic(m_window[index]);
}
// Present the contents of the swap chain to the screen.
void DeviceResources::Present(int index)
{
HRESULT hr = E_FAIL;
if (m_options & c_AllowTearing)
{
hr = m_swapChain[index]->Present(0, DXGI_PRESENT_ALLOW_TEARING);
Print(L"TRACE: Present Present %i \n", index);
}
else
{
hr = m_swapChain[index]->Present(1, 0);
}
m_d3dContext->DiscardView(m_d3dRenderTargetView[index].Get());
if (m_d3dDepthStencilView[index])
{
// Discard the contents of the depth stencil.
m_d3dContext->DiscardView(m_d3dDepthStencilView[index].Get());
}
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
HandleDeviceLost(index);
}
else
{
ThrowIfFailed(hr);
if (!m_dxgiFactory->IsCurrent())
{
CreateFactory();
}
}
}
void DeviceResources::CreateFactory()
{
ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(m_dxgiFactory.ReleaseAndGetAddressOf())));
}
void DeviceResources::GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
{
...
}
I'm trying to create an opengl context (ogl 4.5 at least) and render to it; it works fine with SDL2 but I can't figure out why it doesn't with Win32: I'm trying the screen color to RGBA(1, 0, 0, 1) with glClearColor()/glClear, but nothing seems to happen. Here is my code:
--EDIT I updated the code as you suggested but still, nothing seems rendered; also the problem is not because of gl 3.x/4.x features because I initialized GLEW after having created a wiggle context
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HGLRC ourOpenGLRenderingContext;
bool running = true;
int WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = L"oglversionchecksample";
wc.style = CS_OWNDC;
if (!RegisterClass(&wc))
return 1;
CreateWindowW(wc.lpszClassName, L"openglversioncheck",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0) > 0)
DispatchMessage(&msg);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
glViewport(0, 0, 100, 100); //render to a viewport of width (100; 100)
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
break;
case WM_CREATE:
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette.
32, //Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, //Number of bits for the depthbuffer
8, //Number of bits for the stencilbuffer
0, //Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
HDC ourWindowHandleToDeviceContext = GetDC(hWnd);
int letWindowsChooseThisPixelFormat;
letWindowsChooseThisPixelFormat = ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd);
SetPixelFormat(ourWindowHandleToDeviceContext, letWindowsChooseThisPixelFormat, &pfd);
ourOpenGLRenderingContext = wglCreateContext(ourWindowHandleToDeviceContext);
wglMakeCurrent(ourWindowHandleToDeviceContext, ourOpenGLRenderingContext);
MessageBoxA(0, (char*)glGetString(GL_VERSION), "OPENGL VERSION", 0);
if(glewInit() != GLEW_OK) {
MessageBoxA(0, (char*)glGetString(GL_VERSION), "Error: Could not init OGL API (GLEW)", 0);
}
}
break;
case WM_CLOSE:
//quit code
wglDeleteContext(ourOpenGLRenderingContext);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Creating a modern OpenGL rendering context in Windows takes a bit more effort. Essentially you first have to create a proxy context to load the necessary extensions, then you create the proper context using those. I wrote a small library that does the internal proxy context housekeeping behind the curtains and lets you get right to the core business without further ado: http://github.com/datenwolf/wglarb
For the sake of StackOverflow best practice of include code in answeres instead of linking here's the main implementation file (it's a mere 238 lines):
/*
Copyright (c) 2014 Wolfgang 'datenwolf' Draxinger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <GL/gl.h>
#include "wglarb.h"
#define wglarb_BuildAssert(cond) ((void)sizeof(char[1 - 2*!(cond)]))
static HANDLE wglarb_intermediary_mutex = NULL;
static DWORD wglarb_intermediary_lock(void)
{
wglarb_BuildAssert( sizeof(PVOID) == sizeof(HANDLE) );
if( !wglarb_intermediary_mutex ) {
/* Between testing for the validity of the mutex handle,
* creating a new mutex handle and using the interlocked
* exchange there is a race... */
/* //// START \\\\ */
HANDLE const new_mutex =
CreateMutex(NULL, TRUE, NULL);
HANDLE const dst_mutex =
InterlockedCompareExchangePointer(
&wglarb_intermediary_mutex,
new_mutex,
NULL );
/* //// FINISH \\\\ */
if( !dst_mutex ) {
/* mutex created in one time initialization and held
* by calling thread. Return signaled status. */
return WAIT_OBJECT_0;
}
/* In this case we lost the race and another thread
* beat this thread in creating a mutex object.
* Clean up and wait for the proper mutex. */
ReleaseMutex(new_mutex);
CloseHandle(new_mutex);
}
return WaitForSingleObject(wglarb_intermediary_mutex, INFINITE);
}
static BOOL wglarb_intermediary_unlock(void)
{
return ReleaseMutex(wglarb_intermediary_mutex);
}
#define WGLARB_INTERMEDIARY_CLASS "wglarb intermediary"
#define WGLARB_INTERMEDIARY_STYLE (WS_CLIPSIBLINGS|WS_CLIPCHILDREN)
#define WGLARB_INTERMEDIARY_EXSTYLE 0
static HWND wglarb_intermediary_hWnd = 0;
static BOOL wglarb_intermediary_create_Wnd(void)
{
HINSTANCE const hInstance = GetModuleHandle(NULL);
WNDCLASS wc;
memset(&wc,0,sizeof(wc));
wc.hInstance = hInstance;
wc.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = WGLARB_INTERMEDIARY_CLASS;
RegisterClass(&wc);
wglarb_intermediary_hWnd =
CreateWindowEx(
WGLARB_INTERMEDIARY_EXSTYLE,
WGLARB_INTERMEDIARY_CLASS,
NULL,
WGLARB_INTERMEDIARY_STYLE,
0,0,0,0,
NULL,NULL,
hInstance,
NULL );
if( !wglarb_intermediary_hWnd ) {
return FALSE;
}
return TRUE;
}
static HDC wglarb_intermediary_hDC = 0;
static BOOL wglarb_intermediary_create_DC(void)
{
if( !wglarb_intermediary_hWnd
&& !wglarb_intermediary_create_Wnd() ) {
return FALSE;
}
wglarb_intermediary_hDC = GetDC(wglarb_intermediary_hWnd);
if( !wglarb_intermediary_hDC ) {
return FALSE;
}
return TRUE;
}
static HGLRC wglarb_intermediary_hRC = 0;
static BOOL wglarb_intermediary_create_RC(void)
{
if( !wglarb_intermediary_hDC
&& !wglarb_intermediary_create_DC() ) {
return FALSE;
}
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd,0,sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_SUPPORT_OPENGL|PFD_GENERIC_ACCELERATED|PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.iLayerType = PFD_MAIN_PLANE;
int iPF;
if( !(iPF = ChoosePixelFormat(wglarb_intermediary_hDC, &pfd))
|| !(SetPixelFormat(wglarb_intermediary_hDC, iPF, &pfd))
|| !(wglarb_intermediary_hRC = wglCreateContext(wglarb_intermediary_hDC))
) {
return FALSE;
}
return TRUE;
}
static BOOL wglarb_intermediary_makecurrent(HDC *hOrigDC, HGLRC *hOrigRC)
{
*hOrigDC = wglGetCurrentDC();
*hOrigRC = wglGetCurrentContext();
if( !wglarb_intermediary_hRC
&& !wglarb_intermediary_create_RC() ) {
return FALSE;
}
return wglMakeCurrent(wglarb_intermediary_hDC, wglarb_intermediary_hRC);
}
HGLRC WINAPI wglarb_CreateContextAttribsARB(
HDC hDC,
HGLRC hShareContext,
const int *attribList)
{
if( WAIT_OBJECT_0 != wglarb_intermediary_lock() ) {
return NULL;
}
HDC hOrigDC;
HGLRC hOrigRC;
if( !wglarb_intermediary_makecurrent(&hOrigDC, &hOrigRC) ) {
wglarb_intermediary_unlock();
return NULL;
}
PFNWGLCREATECONTEXTATTRIBSARBPROC impl =
(PFNWGLCREATECONTEXTATTRIBSARBPROC)
wglGetProcAddress("wglCreateContextAttribsARB");
HGLRC ret = NULL;
if( impl ) {
ret = impl(hDC, hShareContext, attribList);
}
wglMakeCurrent(hOrigDC, hOrigRC);
wglarb_intermediary_unlock();
return ret;
}
BOOL WINAPI wglarb_ChoosePixelFormatARB(
HDC hdc,
const int *piAttribIList,
const FLOAT *pfAttribFList,
UINT nMaxFormats,
int *piFormats,
UINT *nNumFormats)
{
if( WAIT_OBJECT_0 != wglarb_intermediary_lock() ) {
return FALSE;
}
HDC hOrigDC;
HGLRC hOrigRC;
if( !wglarb_intermediary_makecurrent(&hOrigDC, &hOrigRC) ) {
wglarb_intermediary_unlock();
return FALSE;
}
PFNWGLCHOOSEPIXELFORMATARBPROC impl = NULL;
impl = (PFNWGLCHOOSEPIXELFORMATARBPROC)
wglGetProcAddress("wglChoosePixelFormatARB");
if( !impl ) {
/* WGL_EXT_pixel_format uses the same function prototypes
* as the WGL_ARB_pixel_format extension */
impl = (PFNWGLCHOOSEPIXELFORMATARBPROC)
wglGetProcAddress("wglChoosePixelFormatEXT");
}
BOOL ret = FALSE;
if( impl ) {
ret = impl(
hdc,
piAttribIList,
pfAttribFList,
nMaxFormats,
piFormats,
nNumFormats );
}
wglMakeCurrent(hOrigDC, hOrigRC);
wglarb_intermediary_unlock();
return ret;
}
Look at the code for SDL to see what it does - I think there's some faffing about to get a context with modern (>=3 or >=4) OpenGL.
https://www.opengl.org/wiki/Creating_an_OpenGL_Context_%28WGL%29
I am pretty new to DirectX 10 programming, and I have been trying to do the following with my limited skills..
I am trying to display an Image from one machine on to another output device(Another Monitor/TV) connected via HDMI. I researched on it and came to know that DXGI can be pretty useful for rendering purposes. Moreover while researching further I came across this link here. It does show how to display different images on multiple monitors connected to the main machine but it requires extended display for that.
My requirement is that when I run the code It should render the image on another output device without making it an extended display.
Approcah I am trying is that I am enumerating Video Adapters(which in my case is 1 ) and and then enumerating outputs available which should be two in numbers as I have an HDMI out connected to my PC. But if I do not set extended display it shows only one output available in my enumerated outputs array and if I extend the display it shows two of them.Once I am done with enumerating outputs I want to Render that image on desired output.
As far as i know every video adapter has a port for HDMI connected to it.
I wonder, if there is way I can access that port programatically and could render the image using that port??
Other than MSDN, documentation or explanation of those concepts are rather limited, so any help would be very welcome. Here is some code I have :
// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include<vector>
#include<iostream>
#include <sstream>
#include<dxgi.h>
using namespace std;
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxgi.lib")
std::vector<IDXGIAdapter*> EnumerateAdapters();
void PrintAdapterInfo(IDXGIAdapter* pAdapter);
std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter);
void PrintOutputInfo(IDXGIOutput* output);
std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output);
void PrintDisplayModeInfo(DXGI_MODE_DESC* pModeDesc);
// global declarations
IDXGISwapChain *swapchain; // the pointer to the swap chain interface
ID3D11Device *dev; // the pointer to our Direct3D device interface
ID3D11DeviceContext *devcon; // the pointer to our Direct3D device context
ID3D11RenderTargetView *backbuffer; // the pointer to our back buffer
IDXGIAdapter *pAdapter;
IDXGIAdapter* adapter = NULL;
IDXGIFactory1* factory = NULL;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
HWND hWnd;
std::vector<IDXGIOutput*> outputArray;
int nCmdShow;
// function prototypes
void InitD3D(HWND hWnd); // sets up and initializes Direct3D
void RenderFrame(void); // renders a single frame
void CleanD3D(void); // closes Direct3D and releases memory
void CreateWindowsForOutputs();
void GetAdapter();
void MultiRender();
void CreateSwapChainsAndViews();
std::vector<IDXGIAdapter*> EnumerateAdapters();
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
struct WindowDataContainer
{
//Direct3D 10 stuff per window data
IDXGISwapChain* swapChain;
ID3D11RenderTargetView* renderTargetView;
ID3D11DepthStencilView* depthStencilView;
// window goodies
HWND hWnd;
int width;
int height;
};
std::vector<WindowDataContainer*> WindowsArray;
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
std::cout << "Hello \nworld!"; // Will show a popup
std::vector<IDXGIAdapter*> adapters = EnumerateAdapters();
for(std::vector<IDXGIAdapter*>::iterator itor = adapters.begin(); itor != adapters.end(); ++itor)
{
//PrintAdapterInfo(*itor);
// Get Output info
std::vector<IDXGIOutput*> outputArray = EnumerateOutputs(*itor);
for(std::vector<IDXGIOutput*>::iterator outputItor = outputArray.begin(); outputItor != outputArray.end(); ++outputItor)
{
// PrintOutputInfo(*outputItor);
// Get display mode list
std::vector<DXGI_MODE_DESC*> modeList = GetDisplayModeList(*outputItor);
for(std::vector<DXGI_MODE_DESC*>::iterator modeItor = modeList.begin(); modeItor != modeList.end(); ++modeItor)
{
// PrintDisplayModeInfo(*modeItor);
}
}
CreateWindowsForOutputs();
MSG msg;
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if(msg.message == WM_QUIT)
break;
}
MultiRender();
}
//std::getchar();
// return 0;
}
//std:getchar();
}
std::vector<IDXGIAdapter*> EnumerateAdapters()
{
// Create DXGI factory
IDXGIFactory1* pFactory = NULL;
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory));
if (FAILED(hr))
{
MessageBox(NULL, L"Create DXGI factory failed", L"Error", 0);
}
// Enumerate devices
IDXGIAdapter* pAdapter = NULL;
std::vector<IDXGIAdapter*> vAdapters;
for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
vAdapters.push_back(pAdapter);
}
if (pFactory)
{
pFactory->Release();
pFactory = NULL;
}
return vAdapters;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.SampleDesc.Quality = 0; // multisample quality level
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain( NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = 800;
viewport.Height = 600;
devcon->RSSetViewports(1, &viewport);
}
// this is the function used to render a single frame
void RenderFrame(void)
{
// clear the back buffer to a deep blue
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
// do 3D rendering on the back buffer here
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
// close and release all existing COM objects
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}
//Acquiring the outputs on our adapter
std::vector<IDXGIOutput*> EnumerateOutputs(IDXGIAdapter* pAdapter)
{
//std::vector<IDXGIOutput*> outputs;
IDXGIOutput* pOutput = NULL;
for (UINT i = 0; pAdapter->EnumOutputs(i, &pOutput) != DXGI_ERROR_NOT_FOUND; ++i)
{
outputArray.push_back(pOutput);
}
return outputArray;
}
void CreateWindowsForOutputs()
{ // std::vector<IDXGIOutput*> outputArray;
for( int i = 0; i < outputArray.size(); ++i )
{
IDXGIOutput* output = outputArray.at(i);
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc( &outputDesc );
int x = outputDesc.DesktopCoordinates.left;
int y = outputDesc.DesktopCoordinates.top;
int width = outputDesc.DesktopCoordinates.right - x;
int height = outputDesc.DesktopCoordinates.bottom - y;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = {0, 0, 800, 600};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
// Don't forget to clean this up. And all D3D COM objects.
WindowDataContainer* window = new WindowDataContainer;
window->hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);
// show the window
ShowWindow( window->hWnd, SW_SHOWDEFAULT );
// InitD3D(hWnd);
CreateSwapChainsAndViews();
// set width and height
window->width = width;
window->height = height;
std::vector<WindowDataContainer*> windowsArray;
// shove it in the std::vector
windowsArray.push_back(window);
//if first window, associate it with DXGI so it can jump in
// when there is something of interest in the message queue
// think fullscreen mode switches etc. MSDN for more info.
// if(i == 0)
// factory->MakeWindowAssociation( window->hWnd, 0 );
}
}
std::vector<DXGI_MODE_DESC*> GetDisplayModeList(IDXGIOutput* output)
{
UINT num = 0;
DXGI_FORMAT format = DXGI_FORMAT_R32G32B32A32_TYPELESS;
UINT flags = DXGI_ENUM_MODES_INTERLACED | DXGI_ENUM_MODES_SCALING;
// Get number of display modes
output->GetDisplayModeList(format, flags, &num, 0);
// Get display mode list
DXGI_MODE_DESC * pDescs = new DXGI_MODE_DESC[num];
output->GetDisplayModeList(format, flags, &num, pDescs);
std::vector<DXGI_MODE_DESC*> displayList;
for(int i = 0; i < num; ++i)
{
displayList.push_back(&pDescs[i]);
}
return displayList;
}
void CreateSwapChainsAndViews()
{
std::vector<WindowDataContainer*> windowsArray;
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// get the dxgi device
IDXGIDevice* DXGIDevice = NULL;
dev->QueryInterface( IID_IDXGIDevice, ( void** )&DXGIDevice ); // COM stuff, hopefully you are familiar
// create a swap chain
DXGI_SWAP_CHAIN_DESC swapChainDesc;
// fill it in
WindowDataContainer *p_Window = new WindowDataContainer;
HRESULT hr = factory->CreateSwapChain( DXGIDevice, &swapChainDesc, &p_Window->swapChain );
DXGIDevice->Release();
DXGIDevice = NULL;
// get the backbuffer
ID3D11Texture2D* backBuffer = NULL;
hr = window->swapChain->GetBuffer( 0, IID_ID3D11Texture2D, ( void** )&backBuffer );
// get the backbuffer desc
D3D11_TEXTURE2D_DESC backBufferDesc;
backBuffer->GetDesc( &backBufferDesc );
// create the render target view
D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;
// fill it in
dev->CreateRenderTargetView( backBuffer, &RTVDesc, &window->renderTargetView );
backBuffer->Release();
backBuffer = NULL;
// Create depth stencil texture
ID3D11Texture2D* depthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
// fill it in
dev->CreateTexture2D( &descDepth, NULL, &depthStencil );
// Create the depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
// fill it in
dev->CreateDepthStencilView( depthStencil, &descDSV, &window->depthStencilView );
}
}
void MultiRender( )
{
std::vector<WindowDataContainer*> windowsArray;
// Clear them all
for( int i = 0; i < windowsArray.size(); i++ )
{
WindowDataContainer* window = windowsArray.at(i);
// There is the answer to your second question:
devcon->OMSetRenderTargets( 1, &window->renderTargetView, NULL );
// Don't forget to adjust the viewport, in fullscreen it's not important...
D3D11_VIEWPORT Viewport;
Viewport.TopLeftX = 0;
Viewport.TopLeftY = 0;
Viewport.Width = window->width;
Viewport.Height = window->height;
Viewport.MinDepth = 0.0f;
Viewport.MaxDepth = 1.0f;
devcon->RSSetViewports( 1, &Viewport );
// TO DO: AMAZING STUFF PER WINDOW
}
}
//std::vector<IDXGIOutput*> outputArray; // contains outputs per adapter
void EnumOutputsOnAdapter()
{
IDXGIOutput* output = NULL;
for(int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
{
// get the description
DXGI_OUTPUT_DESC outputDesc;
HRESULT hr = output->GetDesc( &outputDesc );
outputArray.push_back( output );
}
}
// applicable for multiple ones with little effort
void GetAdapter()
{
// remember, we assume there's only one adapter (example purposes)
for( int i = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters( i, &adapter ); ++i );
{
// get the description of the adapter, assuming no failure
DXGI_ADAPTER_DESC adapterDesc;
HRESULT hr = adapter->GetDesc( &adapterDesc );
// Getting the outputs active on our adapter
EnumOutputsOnAdapter();
}
}
I started to lean c++ and directx11 a few days back.
So I am no expert at it. .Please be kind enough to explain me why it had occurred ...
I created the window and stuff correctly.Even the Swapchain initializtion proceeded as expected.But I am stuck at render Targetview Initializtion...
When ever i debug it gives me the following error
dxgiDevice 0x008959ac <Information not available, no symbols loaded for d3d11.dll> IDXGIDevice
I dont know what am I doing wrong here.I have included Static libraries(dxgi.lib
d3dx11.lib
d3d11.lib
dxguid.lib
D3DCompiler.lib) and linked correctly the header files and libraries as well..
The error seems to arise from this line
SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),(LPVOID*)(&backBuffer));
I dont know what to do..It has gotten me really frustrated.
Please do help me out here..I will be very thank full
Thanks
Here is the full code
#include <Windows.h>
#include <windowsx.h>
#include <D3D11.h>
#include <D3DX11.h>
#include <D3DX10.h>
using namespace std;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
bool InitWindowClass(HINSTANCE hinst,int shw,HWND * _hwnd,WNDCLASSEX * exClass);
RECT windowWidth = {0,0, 1000,768};
int WINAPI WinMain(HINSTANCE inst,HINSTANCE previnst,LPSTR cmdLine,int show)
{
// Window Params
HWND hwnd;
WNDCLASSEX exClass;
MSG msg;
// Iniitaliztion
SecureZeroMemory(&hwnd,sizeof(HWND));
SecureZeroMemory(&exClass,sizeof(exClass));
SecureZeroMemory(&msg,sizeof(MSG));
// Directx 11 Functionalities
#pragma region Create the device
D3D_FEATURE_LEVEL featureLevels[4] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1 , D3D_FEATURE_LEVEL_10_0 , D3D_FEATURE_LEVEL_9_1};
D3D_FEATURE_LEVEL feature_LEVEL;
ID3D11Device * d3dDevice = 0;
ID3D11DeviceContext * d3dContext = 0;
HRESULT hr = D3D11CreateDevice(0,
D3D_DRIVER_TYPE_HARDWARE,
0,
0, // No flags
featureLevels,4,
D3D11_SDK_VERSION,
&d3dDevice,
&feature_LEVEL,&d3dContext);
if(FAILED(hr))
{
MessageBox(hwnd,L"FAiled TO CREATE DEVICE",L"ERROR",0);
}
#pragma endregion
#pragma region Multisampling
UINT multisampleQuality;
d3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_B8G8R8A8_UNORM,4,&multisampleQuality);
#pragma endregion
#pragma region DescribeSwapChain
DXGI_SWAP_CHAIN_DESC swapDesc;
// Allocate Mommory
SecureZeroMemory(&swapDesc,sizeof(DXGI_SWAP_CHAIN_DESC));
swapDesc.BufferDesc.Width = 1000;
swapDesc.BufferDesc.Height = 768;
swapDesc.BufferDesc.RefreshRate.Numerator= 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//MSAA
swapDesc.SampleDesc.Count = 4;
swapDesc.SampleDesc.Quality = multisampleQuality;
//BackBuffer
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.BufferCount = 1;
swapDesc.OutputWindow = hwnd;
swapDesc.Windowed = true;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Flags = 0;
#pragma endregion
#pragma region CreateSwapChain
#pragma region Obtain DXGIFactory
// DXGIFactory >> DXGIAdaptor >> DXGIDevice
// Get the DXGI device
IDXGIDevice * dxgiDevice = 0;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice),(void**)&dxgiDevice);
// Obtain DXGIAdaptor
IDXGIAdapter * dxgiAdaptor = 0;
dxgiDevice->GetParent(__uuidof(IDXGIAdapter),(void**)&dxgiAdaptor);
IDXGIFactory * dxgiFactory = 0;
dxgiAdaptor->GetParent(__uuidof(IDXGIFactory),(void**)&dxgiFactory);
#pragma endregion
IDXGISwapChain * SwapChain = 0;
SecureZeroMemory(&SwapChain,sizeof(IDXGISwapChain));
dxgiFactory->CreateSwapChain(d3dDevice,&swapDesc,&SwapChain);
dxgiAdaptor->Release();
dxgiDevice->Release();
dxgiFactory->Release();
#pragma endregion
#pragma region Create Render Target View
ID3D11RenderTargetView * RenderTarget = 0;
ID3D11Texture2D * backBuffer = 0;
SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),(LPVOID*)(&backBuffer));
d3dDevice->CreateRenderTargetView(backBuffer,NULL,&RenderTarget);
backBuffer->Release();
#pragma endregion
if(InitWindowClass(inst,show,&hwnd,&exClass))
{
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,hwnd,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
// Update Sequences
}
}
}
return msg.wParam;
}
// Initialize and show the Window
bool InitWindowClass(HINSTANCE hinst,int shw,HWND * _hwnd,WNDCLASSEX * exClass)
{
HWND hwnd2 ;
SecureZeroMemory(&hwnd2,sizeof(HWND));
exClass->cbSize = sizeof(WNDCLASSEX);
exClass->hCursor = LoadCursor(0,IDC_ARROW);
exClass->hInstance = hinst;
exClass->lpfnWndProc = WndProc;
exClass->lpszClassName = L"DX_Test";
exClass->lpszMenuName = L"Test";
exClass->hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
RegisterClassEx(exClass);
AdjustWindowRect(&windowWidth,WS_OVERLAPPEDWINDOW,false);
(*_hwnd) = CreateWindowEx(0,L"DX_Test",L"Test",WS_OVERLAPPEDWINDOW,500,200,windowWidth.left,windowWidth.top,NULL,NULL,hinst,0);
ShowWindow((*_hwnd),shw);
UpdateWindow(*_hwnd);
return true;
}
// Message Loop
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch (msg)
{
case WM_LBUTTONDBLCLK:
MessageBox(hwnd,L"Prressed Button 1",L"Mouse 1",0);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_KEYDOWN:
if(wparam == VK_ESCAPE)
DestroyWindow(hwnd);
return 0;
}
return DefWindowProc(hwnd,msg,wparam,lparam);
}
The "error message" you're talking about comes from the VS debugger: all it is telling you is that it doesn't have any debugging symbols for d3d11.dll. In other words this is not your problem - it's a red herring.
To solve the problem, you need some error checking. IDXGISwapChain::GetBuffer returns a HRESULT, which you should check for errors, e.g.:
HRESULT res = SwapChain->GetBuffer(...);
if (!SUCCEEDED(res))
{
std::cerr << "Error getting buffer from swap chain: " << std::hex << res << std::endl;
}
You can then check the result against the values in this set of documentation to find out specifically what the error was.
Note that you should probably do similar things for a lot of your other DirectX calls as well.