How can I render the images on the monitor (or TV) connected to HDMI port of my computer - c++

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();
}
}

Related

Direct2D bitmap RAM usage optimization

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

D3D11CreateDeviceAndSwapChain fails with S_False on different computer

I've made quite a bit of progress since the last time I asked a question. I've got a really cool build now with a terrain mesh with mountains and lakes:
LakeAndMountains
I made a release build, debugged it, and now it works just fine on my computer. I can take the application folder and move it around on my computer and run the .exe file with no issues. However, when I copy the application directory over to my other computer (and my friend's computer), it fails during the D3D11CreateDeviceAndSwapChain step with an HR of S_False.
For both my other computer and my friend's computer, it triggers only the if(failed(hr)) after the create function is called, and it says dev/devcon/swapchain are all NULL. Because they are all null, when it hits the function from swapchain, it crashes with an access violation error.
I searched for a few days looking for solutions, but I have yet to see one that had the S_FALSE occur. I tried some of the more straightforward answers but got nothing. All the computers are running 64bit on 64 bit OS, all have DirectX12, all are high end gaming PCs, my other computer actually has VS2017CE as well set up for c++ game programming, but they both still fail on that line. I'd really appreciate it if anyone could give me some guidance on where to begin deciphering why a release build works on my computer but not on anyone else's computer. Here is the code where it gets initialized, as well as the code for the window creation (code is excerpted to just the relevant parts of the functions):
WinMain:
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//MessageBox(NULL, "Start of WinMain", "WinMain", 0);
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
//Screen size variables
long screenWidth = 1280;
long screenHeight = 720;
UINT screenWidthUINT = 1280;
UINT screenHeightUINT = 720;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
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 = "WindowClass1";
// register the window class
RegisterClassEx(&wc);
RECT wr = { 0, 0, screenWidth, screenHeight }; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
"WindowClass1",
"Game",
WS_OVERLAPPEDWINDOW,
0, // x-position of the window
0, // y-position of the window
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
NULL,
NULL,
hInstance,
NULL);
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
//MessageBox(NULL, "called ShowWindow", "WinMain", 0);
/*****************************************
// GAME ENGINE INITIALIZATION
******************************************/
//Need to initialize the graphics engine. This passes the window pointer through the
//game engine to the D3D engine so it knows what window to look at.
//MessageBox(NULL, "Calling InitGraphics", "WinMain", 0);
InitGraphics(hWnd);
InitGraphics:
//DEVICE CREATION
#include Windows.h
#include <windowsx.h>
#include <d3d11.h>
#include <DirectXMath.h>
#include <D3Dcompiler.h>
#include <dxgi.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
#include "DirectXDeviceEngine.h"
using namespace DirectX;
InitGraphics(HWND hWnd)
{
//call at start to initialize D3DX
if (hWnd == NULL)
{
MessageBox(NULL, "hWnd was NULL", "DirectXDeviceEngine", 0);
}
HRESULT hr;
//initialize swap chain
//Describe our Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
bufferDesc.Width = winWidth;
bufferDesc.Height = winHeight;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
// 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 = bufferDesc;
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 = 4; // how many multisamples
scd.SampleDesc.Quality = 1;
scd.Windowed = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // windowed/full-screen mode
scd.Flags = 0;
// create a device, device context and swap chain using the information in the scd struct
dev = NULL;
devcon = NULL;
swapchain = NULL;
hr = D3D11CreateDeviceAndSwapChain(
NULL, //null
D3D_DRIVER_TYPE_HARDWARE, //driver type
NULL, //handle to a software rasterizer, should be null if driver type isn't software
NULL, //UINT device creation flags, can be ORed together
NULL, //D3D Feature level, when NULL defaults to 11.0-9.1 feature levels
NULL, //the number of elements in the D3D feature level array
D3D11_SDK_VERSION, //set to D3D11_SDK_VERSION
&scd, //reference to the swap chain desc
&swapchain, //reference to the pointer to the swap chain
&dev, //reference to the pointer to the device
NULL, //returns a reference to the first supported element in the feature level array
&devcon); //reference to the pointer to the device context
if (FAILED(hr))
{
//CODE FALLS INTO THIS BLOCK ON OTHER COMPUTER
MessageBox(NULL, "Create Device and SwapChain FAILED", "DirectXDeviceEngine", 0);
if (swapchain == NULL)
{
MessageBox(NULL, "swapchain was NULL", "DirectXDeviceEngine", 0);
}
if (dev == NULL)
{
MessageBox(NULL, "dev was NULL", "DirectXDeviceEngine", 0);
}
if (devcon == NULL)
{
MessageBox(NULL, "devcon was NULL", "DirectXDeviceEngine", 0);
}
}
//prepare buffers
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
//VVVV CODE THEN CRASHES ON NEXT LINE BECAUSE SWAPCHAIN IS NULL VVVV
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
Thanks in advance.
----UPDATE 2017/09/08-----
So I swapped some code around but I still get the error on the other computer. Current code looks like this:
//call at start to initialize D3DX
if (&hWnd == NULL)
{
MessageBox(NULL, "hWnd was NULL", "DirectXDeviceEngine", 0);
}
HRESULT hr;
// create a device, device context and swap chain using the information in the scd struct
dev = NULL;
devcon = NULL;
swapchain = NULL;
D3D_FEATURE_LEVEL lvl[] = {
D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 };
DWORD createDeviceFlags = 0;
hash ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
hash endif
D3D_FEATURE_LEVEL fl;
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
createDeviceFlags, lvl, _countof(lvl),
D3D11_SDK_VERSION, &dev, &fl, &devcon);
if (hr == E_INVALIDARG)
{
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
createDeviceFlags, &lvl[1], _countof(lvl) - 1,
D3D11_SDK_VERSION, &dev, &fl, &devcon);
}
if (FAILED(hr))
{
MessageBox(NULL, "Create Device Failed", "DirectXDeviceEngine", 0);
}
IDXGIDevice * dxgiDevice = 0;
dev->QueryInterface(__uuidof(IDXGIDevice), (void **)& dxgiDevice);
IDXGIAdapter * dxgiAdapter = 0;
dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void **)& dxgiAdapter);
IDXGIFactory * dxgiFactory = 0;
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void **)& dxgiFactory);
//initialize swap chain
//Describe our Buffer
DXGI_MODE_DESC bufferDesc;
ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));
/*bufferDesc.Width = winWidth;
bufferDesc.Height = winHeight;
bufferDesc.RefreshRate.Numerator = 60;
bufferDesc.RefreshRate.Denominator = 1;
*/
bufferDesc.Width = 0;
bufferDesc.Height = 0;
bufferDesc.RefreshRate.Numerator = 0;
bufferDesc.RefreshRate.Denominator = 1;
bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
// 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 = bufferDesc;
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 = 4; // how many multisamples
scd.SampleDesc.Quality = 1;
scd.Windowed = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // windowed/full-screen mode
scd.Flags = 0;
hr = dxgiFactory->CreateSwapChain(dev, &scd, &swapchain);
if (FAILED(hr))
{
//fails here
MessageBox(NULL, "Create Swap Chain Failed", "DirectXDeviceEngine", 0);
}
if (dxgiDevice != NULL)
{
dxgiDevice->Release();
}
if (dxgiAdapter != NULL)
{
dxgiAdapter->Release();
}
if (dxgiFactory != NULL)
{
dxgiFactory->Release();
}
//prepare buffers
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
So, there is still some weird stuff happening here I'm not getting. If someone has an example of how to use FindClosestMatchingMode properly, I'd really appreciate it.
There is one other really peculiar thing though. When I am in the debugger on my laptop, the variable hWnd has a value, but the compiler says that it is Unused and can't display a value for it. Is this normal or could this be the source of the problem as hWnd is used in the Swap Chain Description? How can hWnd be bad/unused on the other computer but not on my desktop?
Thanks again.
So I FINALLY found the cause of the issue. For some reason, the Count 4 Quality 1 MSAA was not working on the other computer. When I set it to 1/0, it ran perfectly. I'll need to look into how to properly enumerate the MSAA stuff so it can be adjusted depending on the computer.

C++ and directx 11 Error no symbols loaded for dxgi.dll

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.

SetLayeredWindowAttributes to make a window transparent is only working part of the time

I'm trying to make a window transparent so that only part of its contents are visible, I've tried using SetLayeredWindowAttributes to make this happen, this made the window transparent as I wanted, however it only works that way when part of the windows picture is outside of the visible area of my desktop. For some reason whenever the window is fully on screen it re-draws its black background (the color I use for transparency that's meant not to be seen.) Here is a video example of the problem. I'm not sure what exactly is causing this to just to be safe I'm posting the full code.
#define _WIN32_WINNT 0x501
#include "C:\Program Files\Microsoft DirectX SDK (August 2008)\Include\D3dx9core.h"
#include "C:\Documents and Settings\Death\My Documents\Downloads\DXSprite\DXSprite\resource.h"
#include <windows.h>
#include <string>
#include <stdio.h>
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND g_hWnd = NULL;
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
ID3DXSprite * g_pD3DXSprite = NULL;
LPDIRECT3DTEXTURE9 g_pTexture = NULL;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT InitializeD3D ( );
void RenderFrame ( );
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
HRESULT hr;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDC_DXSPRITE);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( WS_EX_LAYERED, "MY_WINDOWS_CLASS",
"Direct3D 9 - ID3DXSprite Example",
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
SetLayeredWindowAttributes(g_hWnd, RGB(0x00,0x00,0x00), 0, LWA_COLORKEY});
ShowWindow( g_hWnd, nCmdShow );
//----------------------------------------------------------------
// Create the DirectX device
//----------------------------------------------------------------
if (FAILED( InitializeD3D()))
return 0;
//----------------------------------------------------------------
// CREATE THE ID3DXSprite
//----------------------------------------------------------------
// Create the ID3DXSprite interface object
hr = D3DXCreateSprite(g_pD3DDevice, &g_pD3DXSprite );
if( FAILED(hr) )
return hr;
//----------------------------------------------------------------
// LOAD THE TEXTURE FOR THE SPRITE
//----------------------------------------------------------------
// --------------------------------------------------------
// Load the texture. I decided to use the extended
// version of the texture loading function just to show what
// it would look like.
// The texture was created with Photoshop with a transparent
// background to start with. Then line cross hairs were added.
//
// Note - If you don't use a texture image that has a power of
// 2 size for the width or height then the image may not load
// properly. This image is 256x256.
//
D3DXCreateTextureFromFileEx(
g_pD3DDevice,
"C:\\Documents and Settings\\Death\\My Documents\\45handold2.tga", // Our texture image!
D3DX_DEFAULT, // width
D3DX_DEFAULT, // height
D3DX_DEFAULT, // MIP levels
0, // usage
D3DFMT_DXT1, // texture format
D3DPOOL_MANAGED, // mem pool
D3DX_DEFAULT, // filter
D3DX_DEFAULT, // MIP filter
0, // transparent color key
NULL, // image info struct
NULL, // palette
&g_pTexture); // the returned texture, if success
if ( FAILED(hr) )
return hr;
// ---------
// Main Loop
// ---------
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
}
// -------------------------
// Release directx resources
// -------------------------
if (g_pD3DXSprite)
{
g_pD3DXSprite->Release();
g_pD3DXSprite = NULL;
}
if (g_pTexture)
{
g_pTexture->Release();
g_pTexture = NULL;
}
if (g_pD3DDevice)
{
g_pD3DDevice->Release();
g_pD3DDevice = NULL;
}
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return (int)uMsg.wParam;
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
case WM_CLOSE:
{
PostQuitMessage(0);
}
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
{
RenderFrame();
return DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
return 0;
}
//-----------------------------------------------------------------------------
// Name: InitializeD3D()
// Desc: Create DirectX interface objects
// Initialize the view matrix.
// Setup render states that will not need changing throughout
// the life of the application.
//-----------------------------------------------------------------------------
HRESULT InitializeD3D( )
{
HRESULT hr;
// Create a direct 3D interface object
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
if( g_pD3D == NULL )
{
// TO DO: Respond to failure of Direct3DCreate9
return E_FAIL;
}
D3DDISPLAYMODE d3ddm;
if( FAILED( hr = g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
// TO DO: Respond to failure of GetAdapterDisplayMode
return hr;
}
//
if( FAILED( hr = g_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
d3ddm.Format, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
{
if( hr == D3DERR_NOTAVAILABLE )
// POTENTIAL PROBLEM: We need at least a 16-bit z-buffer!
return hr;
}
//
// Do we support hardware vertex processing? If so, use it.
// If not, downgrade to software.
//
D3DCAPS9 d3dCaps;
if( FAILED( hr = g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, &d3dCaps ) ) )
{
// TO DO: Respond to failure of GetDeviceCaps
return hr;
}
DWORD dwBehaviorFlags = 0;
if( d3dCaps.VertexProcessingCaps != 0 )
dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
//
// Everything checks out - create a simple, windowed device.
//
D3DPRESENT_PARAMETERS d3dpp;
memset(&d3dpp, 0, sizeof(d3dpp));
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
// Attempt to create a HAL device, end app on failure just to keep things
// simple. In other words we are not trying to create a REF device if the
// HAL fails.
if( FAILED( hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd,
dwBehaviorFlags, &d3dpp, &g_pD3DDevice ) ) )
{
// char blah[100];
// snprintf (blah, 1000, "%d", hr);
//MessageBox (NULL,blah,NULL,NULL);
}
// If we get here everything worked!
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: RenderFrame()
// Desc: Draw the image to the framebuffer.
//-----------------------------------------------------------------------------
void RenderFrame( )
{
if (!g_pD3DDevice && !g_pD3DXSprite && !g_pTexture)
return;
// Clear the frame & depth buffer ready for drawing (Black color)
g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0 );
g_pD3DDevice->BeginScene();
{
//-------------------------
// Render the sprite
//
D3DXVECTOR3 vecPos = D3DXVECTOR3(0,0,0);
if (g_pD3DXSprite && g_pTexture)
{
g_pD3DXSprite->Begin( D3DXSPRITE_ALPHABLEND );
g_pD3DXSprite->Draw(g_pTexture, NULL, NULL, &vecPos, 0xffffffff);
g_pD3DXSprite->End();
}
}
g_pD3DDevice->EndScene();
// Frame buffer to Front buffer
g_pD3DDevice->Present( NULL, NULL, NULL, NULL );
}
The problem you're running into is basically that there used to be two entirely separate rendering stacks in Windows: GDI and Direct3D. They didn't really talk to one another at all, so standard windowing and GDI APIs don't really know anything about Direct3D. When Vista came along they unified the two driver stacks, but the GDI code (generally speaking) still knows nothing about Direct3D, even if it internally uses some Direct3D behind the scenes (for desktop composition).
In short, SetLayeredWindowAttributes as well as UpdateLayeredWindow cannot and do not know about your Direct3D swapchain. If you had tried this back on Windows XP or 2000 I expect you would have gotten some really funky visual results. There are some really good reasons for this, I should add. For example, in the GDI world, using UpdateLayeredWindow to set a bitmap with per-pixel alpha actually results in places with an alpha value of zero being treated as not part of the window. In other words, clicks pass through to the window underneath. In order to implement this with Direct3D, the system would have to read back the Direct3D texture from GPU to CPU memory, which is quite expensive, and then perform the hit test.
One solution, of course, is to use GDI to render the window, including the color key. I'm assuming you ruled that out for performance reasons.
I'm not entirely sure of the visual results you are expecting, but if you want to render arbitrary alpha-blended content in a window with full hardware acceleration and no window border, you can create a borderless window (e.g. just WS_POPUP for its window style) and call DwmExtendFrameIntoClientArea passing -1 for all the margins. Then, create your swap-chain with the D3DFMT_A8R8G8B8 pixel format or the DXGI equivalent for Direct3D 10/11 (which is the native format DWM uses to render windows) and render into it. You now have a window that contains only your alpha-blended content superimposed on the desktop. There is an older article on CodeProject about this very topic.

How can I render multiple windows with DirectX 9 in C?

I've already asked this question at https://gamedev.stackexchange.com/questions/50374/how-can-i-render-multiple-windows-with-directx-9-in-c but I have not yet received an answer.
I'm trying to render multiple windows, using DirectX 9 and swap chains, but even though I create 2 windows, I only see the first one that I've created. My RendererDX9 header is this:
#include <d3d9.h>
#include <Windows.h>
#include <vector>
#include "RAT_Renderer.h"
namespace RAT_ENGINE
{
class RAT_RendererDX9 : public RAT_Renderer
{
public:
RAT_RendererDX9();
~RAT_RendererDX9();
void Init(RAT_WindowManager* argWMan);
void CleanUp();
void ShowWin();
private:
LPDIRECT3D9 renderInterface; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 renderDevice; // Our rendering device
LPDIRECT3DSWAPCHAIN9* swapChain; // Swapchain to make multi-window rendering possible
WNDCLASSEX wc;
std::vector<HWND> hwindows;
void Render(int argI);
};
}
And my .cpp file is this:
#include "RAT_RendererDX9.h"
static LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
namespace RAT_ENGINE
{
RAT_RendererDX9::RAT_RendererDX9() : renderInterface(NULL), renderDevice(NULL)
{
}
RAT_RendererDX9::~RAT_RendererDX9()
{
}
void RAT_RendererDX9::Init(RAT_WindowManager* argWMan)
{
wMan = argWMan;
// Register the window class
WNDCLASSEX windowClass =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0, 0,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
"foo", NULL
};
wc = windowClass;
RegisterClassEx( &wc );
for (int i = 0; i< wMan->getWindows().size(); ++i)
{
HWND hWnd = CreateWindow( "foo", argWMan->getWindow(i)->getName().c_str(),
WS_OVERLAPPEDWINDOW, argWMan->getWindow(i)->getX(), argWMan->getWindow(i)->getY(),
argWMan->getWindow(i)->getWidth(), argWMan->getWindow(i)->getHeight(),
NULL, NULL, wc.hInstance, NULL );
hwindows.push_back(hWnd);
}
// Create the D3D object, which is needed to create the D3DDevice.
renderInterface = (LPDIRECT3D9)Direct3DCreate9( D3D_SDK_VERSION );
// Set up the structure used to create the D3DDevice. Most parameters are
// zeroed out. We set Windowed to TRUE, since we want to do D3D in a
// window, and then set the SwapEffect to "discard", which is the most
// efficient method of presenting the back buffer to the display. And
// we request a back buffer format that matches the current desktop display
// format.
D3DPRESENT_PARAMETERS deviceConfig;
ZeroMemory( &deviceConfig, sizeof( deviceConfig ) );
deviceConfig.Windowed = TRUE;
deviceConfig.SwapEffect = D3DSWAPEFFECT_DISCARD;
deviceConfig.BackBufferFormat = D3DFMT_UNKNOWN;
deviceConfig.BackBufferHeight = 1024;
deviceConfig.BackBufferWidth = 768;
deviceConfig.EnableAutoDepthStencil = TRUE;
deviceConfig.AutoDepthStencilFormat = D3DFMT_D16;
// Create the Direct3D device. Here we are using the default adapter (most
// systems only have one, unless they have multiple graphics hardware cards
// installed) and requesting the HAL (which is saying we want the hardware
// device rather than a software one). Software vertex processing is
// specified since we know it will work on all cards. On cards that support
// hardware vertex processing, though, we would see a big performance gain
// by specifying hardware vertex processing.
renderInterface->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwindows[0],
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&deviceConfig, &renderDevice );
this->swapChain = new LPDIRECT3DSWAPCHAIN9[wMan->getWindows().size()];
this->renderDevice->GetSwapChain(0, &swapChain[0]);
for (int i = 0; i < wMan->getWindows().size(); ++i)
{
renderDevice->CreateAdditionalSwapChain(&deviceConfig, &swapChain[i]);
}
renderDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); // Set cullmode to counterclockwise culling to save resources
renderDevice->SetRenderState(D3DRS_AMBIENT, 0xffffffff); // Turn on ambient lighting
renderDevice->SetRenderState(D3DRS_ZENABLE, TRUE); // Turn on the zbuffer
}
void RAT_RendererDX9::CleanUp()
{
renderDevice->Release();
renderInterface->Release();
}
void RAT_RendererDX9::Render(int argI)
{
// Clear the backbuffer to a blue color
renderDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
LPDIRECT3DSURFACE9 backBuffer = NULL;
// Set draw target
this->swapChain[argI]->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backBuffer);
this->renderDevice->SetRenderTarget(0, backBuffer);
// Begin the scene
renderDevice->BeginScene();
// End the scene
renderDevice->EndScene();
swapChain[argI]->Present(NULL, NULL, hwindows[argI], NULL, 0);
}
void RAT_RendererDX9::ShowWin()
{
for (int i = 0; i < wMan->getWindows().size(); ++i)
{
ShowWindow( hwindows[i], SW_SHOWDEFAULT );
UpdateWindow( hwindows[i] );
// Enter the message loop
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
if (PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render(i);
}
}
}
}
}
LRESULT CALLBACK MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
//CleanUp();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
//Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
I've made a sample function to make multiple windows:
void RunSample1()
{
//Create the window manager.
RAT_ENGINE::RAT_WindowManager* wMan = new RAT_ENGINE::RAT_WindowManager();
//Create the render manager.
RAT_ENGINE::RAT_RenderManager* rMan = new RAT_ENGINE::RAT_RenderManager();
//Create a window.
//This is currently needed to initialize the render manager and create a renderer.
wMan->CreateRATWindow("Sample 1 - 1", 10, 20, 640, 480);
wMan->CreateRATWindow("Sample 1 - 2", 150, 100, 480, 640);
//Initialize the render manager.
rMan->Init(wMan);
//Show the window.
rMan->getRenderer()->ShowWin();
}
How do I get the multiple windows to work?
The "Swap Chain" approach you used for rendering the multiple windows is sounds good compare to creating multiple devices for multiple screens.
Have you checked the codesampler tutorial for rendering the multiple windows using swap chain. If not, pls find the below link which has a working sample project for rendering the multiple windows using swap chain. This code is purely windows Directx 9 specific but you could added your wrapper to achieve platform agnostic.
Creating Multiple Devices
Using Swap Chain
http://www.codesampler.com/dx9src/dx9src_1.htm