Sign in to follow this  

Explicity linking DirectX 10?

This topic is 2846 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been trying to build a rendering engine that will fall back to DirectX 9 if DirectX 10 is unavailable. At first it seemed like it worked, if there was an error with DX10 then it would fall back... then I tried it on an XP machine, and it said that it couldn't find d3d10.dll. I've determined this to be normal functionality when linking implicitly, and I'd love to know if there's a way to use LoadLibrary to "attempt" the use of DX10 instead of failing when the DLL is not found. As far as I can tell, LoadLibrary only gives you an HInstance from which you can select SPECIFIC functions based on their export name, and this must happen at RUNTIME. Unless I am mistaken, this means I can't just include d3d10.h. What would you experts consider the best course of action? Perhaps a custom "D3D10 Loader" that will load the needed functions from the Library into pointers with the same name, thus confusing the linker into thinking they are internal? EDIT: It's beginning to seem like I can include the header anyway and fool it into using pointers in my CPP files instead of external functions from an explicitly linked DLL. Is this at all correct? EDIT: An extended amount of googling came up with this: http://www.devmaster.net/forums/archive/index.php/t-4845.html I'll try the methods listed here and post back if I still need help. [Edited by - Super Llama on March 1, 2010 3:47:11 PM]

Share this post


Link to post
Share on other sites
Apparently those topics are only for VC++. I use GCC, and I can't seem to find any way of using lazylink with Windows. I'm probably just going to switch to VC++ for the windows version of the project, unless someone can think of something else.

Share this post


Link to post
Share on other sites
Not sure exactly what you're asking, but for dynamically loading D3D, it can be done something like this.

You still include D3D*.h, and use everything as normal. As most functions are class member functions, you don't need to load them from the DLL, only free functions need to be loaded. So basically you just use GetProcAddress("D3D10CreateDeviceAndSwapChain"), use that to set the object up, and once you have the object all member functions will work as usual.

The function pointer types for the free functions are defined in the header for D3D11 and D3D10.1. I recommend using one of them, as there's no reason to use 10.0 (the newer ones work on the same systems, and more, because of feature levels), but you can also define the function pointer for 10.0 yourself.

Here's a minimal example for D3D11 (this will run without linking to any D3D libs). Note that the only function that ever needs to be loaded manually is D3D11CreateDeviceAndSwapChain. If you choose the adapter manually you might also need to load CreateDXGIFactory(1) from dxgi.dll.

#include <windows.h>
#include <D3D11.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Main
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// Register windowclass
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.lpszClassName = TEXT("MyClass");
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&wc);

// Create window
HWND hWnd = CreateWindow(
wc.lpszClassName,
TEXT("D3D11 Window"),
WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);

// Load D3D11 DLL
HMODULE hD3D11 = LoadLibrary(TEXT("d3d11.dll"));
if(hD3D11 == NULL) {
MessageBox(NULL, TEXT("LoadLibrary failed"), TEXT("Error"), MB_OK);
return 0;
}

// Load the D3D11CreateDeviceAndSwapChain function
PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN pfnD3D11CreateDeviceAndSwapChain =
(PFN_D3D11_CREATE_DEVICE_AND_SWAP_CHAIN)GetProcAddress(hD3D11, "D3D11CreateDeviceAndSwapChain");
if(pfnD3D11CreateDeviceAndSwapChain == NULL) {
MessageBox(NULL, TEXT("GetProcAddress failed"), TEXT("Error"), MB_OK);
return 0;
}

// Create device and swapchain
DXGI_SWAP_CHAIN_DESC scd;
IDXGISwapChain *pSwapChain;
ID3D11Device *pDevice;
ID3D11DeviceContext *pDeviceContext;
D3D_FEATURE_LEVEL featureLevel;

ZeroMemory(&scd, sizeof(scd));
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.SampleDesc.Count = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 1;
scd.OutputWindow = hWnd;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Windowed = TRUE;

HRESULT hResult = pfnD3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_DEBUG,
NULL,
0,
D3D11_SDK_VERSION,
&scd,
&pSwapChain,
&pDevice,
&featureLevel,
&pDeviceContext
);
if(FAILED(hResult)) {
MessageBox(NULL, TEXT("D3D11CreateDeviceAndSwapChain failed"), TEXT("Error"), MB_OK);
return 0;
}

// Check what feature level was available
switch(featureLevel) {
case D3D_FEATURE_LEVEL_11_0: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 11.0")); break;
case D3D_FEATURE_LEVEL_10_1: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 10.1")); break;
case D3D_FEATURE_LEVEL_10_0: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 10.0")); break;
case D3D_FEATURE_LEVEL_9_3: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 9.3")); break;
case D3D_FEATURE_LEVEL_9_2: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 9.2")); break;
case D3D_FEATURE_LEVEL_9_1: SetWindowText(hWnd, TEXT("D3D11 Window - Feature Level 9.1")); break;
}

// Render target
ID3D11Texture2D *pBackBuffer;
ID3D11RenderTargetView *pRTV;

pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
pDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRTV);
pBackBuffer->Release();

// Main loop
ShowWindow(hWnd, nCmdShow);

while(true) {
MSG msg;
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
if(msg.message == WM_QUIT)
break;
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else {
// Clear backbuffer
float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
pDeviceContext->ClearRenderTargetView(pRTV, color);

// Present
pSwapChain->Present(1, 0);
}
}

// Release
pSwapChain->SetFullscreenState(FALSE, NULL);

pDeviceContext->ClearState();

pRTV->Release();
pDeviceContext->Release();
pDevice->Release();
pSwapChain->Release();

FreeLibrary(hD3D11);

UnregisterClass(wc.lpszClassName, hInstance);

return 0;
}

// Window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}

return DefWindowProc(hWnd, msg, wParam, lParam);
}

Share this post


Link to post
Share on other sites
Thank you, that was exactly what I wanted to know [smile]

Not only will this work, it will also fit perfectly into my current system. I have a set of namespaces describing each of my supported graphics subsets-- DX9, DX10, and an unfinished DX11 namespace. When the InitDevice function is called, it first tries the selected subset (you can use the command line arguments to change it), then falls back to the previous version if the function fails.

All I'll have to do is stick a LoadLibrary in there and return 0; if it returns NULL, and I've got it made.

Thanks again!

Share this post


Link to post
Share on other sites

This topic is 2846 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this