I'm coding a C++ game from scratch using the Direct-X 12 API.
I'm using a few tutorials: Braynzar Soft Direct-X 12 tutorial, Alian Direct-X 12 and a few others.
Each one I use runs and has no errors. But I have a slight problem.
In professional games and game engines, they can use a dedicated GPU to run their programs and sometimes at a low performance. BUT, when I use this tutorials or I code it myself, it uses both of my GPUs simultaneously. Why is that? Is there some bug within the code? Does Direct-X 12 just multi-GPU automatically? Can I prevent this and how? There wouldn't be a problem with this, but I would like, if possible, to only use on GPU.
Simple code:
int32_t CALLBACK wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int32_t)
{
HRESULT ReturnCode = S_OK;
#ifdef _SCPDebug
ID3D12Debug3* D3D12DebugInterface = nullptr;
IDXGIInfoQueue* DXGIDebugInfoQueue = nullptr;
ReturnCode = D3D12GetDebugInterface(IID_PPV_ARGS(&D3D12DebugInterface));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12DebugInterface->EnableDebugLayer();
D3D12DebugInterface->SetEnableGPUBasedValidation(TRUE);
ReturnCode = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&DXGIDebugInfoQueue));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = DXGIDebugInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = DXGIDebugInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#endif
IDXGIFactory7* DXGIFactory = nullptr;
#ifdef _SCPDebug
ReturnCode = CreateDXGIFactory2(1, IID_PPV_ARGS(&DXGIFactory));
#else
ReturnCode = CreateDXGIFactory2(0, IID_PPV_ARGS(&DXGIFactory));
#endif
if (ReturnCode != S_OK)
{
return ReturnCode;
}
BOOL SupportsVariableRefreshRate = FALSE;
ReturnCode = DXGIFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &SupportsVariableRefreshRate, sizeof(BOOL));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
IDXGIAdapter4* DXGIAdapter = nullptr;
ReturnCode = DXGIFactory->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&DXGIAdapter));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12Device8* D3D12Device = nullptr;
#ifdef _SCPDebug
ID3D12InfoQueue* D3D12DeviceDebugInfoQueue = nullptr;
#endif
ReturnCode = D3D12CreateDevice(DXGIAdapter, D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&D3D12Device));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Device8");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#ifdef _SCPDebug
ReturnCode = D3D12Device->QueryInterface(&D3D12DeviceDebugInfoQueue);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12DeviceDebugInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12DeviceDebugInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
#endif
ID3D12DescriptorHeap* D3D12DSDescriptorHeap = nullptr;
ID3D12Resource2* D3D12DS = nullptr;
D3D12_DESCRIPTOR_HEAP_DESC DescriptorHeapDesc = {};
DescriptorHeapDesc.NumDescriptors = 1;
DescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
DescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
ReturnCode = D3D12Device->CreateDescriptorHeap(&DescriptorHeapDesc, IID_PPV_ARGS(&D3D12DSDescriptorHeap));
if (FAILED(ReturnCode))
{
return ReturnCode;
}
ReturnCode = D3D12DSDescriptorHeap->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Depth Stencil Descriptor Heap");
if (FAILED(ReturnCode))
{
return ReturnCode;
}
D3D12_CLEAR_VALUE OptimizedDepthClearValue;
OptimizedDepthClearValue.DepthStencil.Depth = 1.0f;
OptimizedDepthClearValue.DepthStencil.Stencil = 0;
OptimizedDepthClearValue.Format = DXGI_FORMAT_D32_FLOAT;
D3D12_HEAP_PROPERTIES HeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
D3D12_RESOURCE_DESC HeapDesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, 1920, 1080, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
ReturnCode = D3D12Device->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &HeapDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &OptimizedDepthClearValue, IID_PPV_ARGS(D3D12DS));
if (FAILED(ReturnCode))
{
return ReturnCode;
}
ReturnCode = D3D12DS->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Depth Stencil Heap");
if (FAILED(ReturnCode))
{
return ReturnCode;
}
D3D12_DEPTH_STENCIL_VIEW_DESC DepthStencilViewDesc = {};
DepthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
DepthStencilViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
DepthStencilViewDesc.Flags = D3D12_DSV_FLAG_NONE;
D3D12Device->CreateDepthStencilView(D3D12DS, &DepthStencilViewDesc, D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
ID3D12Fence1* D3D12Fence = nullptr;
uint64_t FenceValue = 0ULL;
HANDLE FenceEvent = nullptr;
ReturnCode = D3D12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&D3D12Fence));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Fence->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Sync::Fence");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
HANDLE FenceEvent = CreateEventW(nullptr, FALSE, FALSE, L"SCP-Site Breach::Engine::Direct-X 12::Sync::Fence Event");
if (FenceEvent == nullptr)
{
return E_UNEXPECTED;
}
ID3D12RootSignature* D3D12RootSignature = nullptr;
{
D3D12_ROOT_SIGNATURE_DESC1 Desc = {};
Desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
Desc.NumParameters = 0;
Desc.NumStaticSamplers = 0;
Desc.pParameters = nullptr;
Desc.pStaticSamplers = nullptr;
D3D12_VERSIONED_ROOT_SIGNATURE_DESC RootSignatureDescVersion = {};
RootSignatureDescVersion.Desc_1_1 = Desc;
RootSignatureDescVersion.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
ID3D10Blob* D3D12SignatureBlob = nullptr;
ID3D10Blob* D3D12ErrorBlob = nullptr;
ReturnCode = D3D12SerializeVersionedRootSignature(&RootSignatureDescVersion, &D3D12SignatureBlob &D3D12ErrorBlob);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->CreateRootSignature(0, D3D12SignatureBlob->GetBufferPointer(), D3D12SignatureBlob->GetBufferSize(), IID_PPV_ARGS(&D3D12RootSignature));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode =D3D12RootSignature->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Root Signature");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12SignatureBlob->Release();
D3D12SignatureBlob = nullptr;
}
D3D12_SHADER_BYTECODE D3D12PixelShader = {};
D3D12_SHADER_BYTECODE D3D12VertexShader = {};
std::ifstream PixelShader("PixelShader.cso", std::ios_base::binary | std::ios_base::in);
auto FileSize = PixelShader.tellg();
PixelShader.seekg(0, std::iostream::end);
FileSize += PixelShader.tellg() - FileSize;
PixelShader.seekg(0, std::iostream::beg);
std::ifstream VertexShader("VertexShader.cso", std::ios_base::binary | std::ios_base::in);
auto FileSize2 = VertexShader.tellg();
VertexShader.seekg(0, std::iostream::end);
FileSize2 += VertexShader.tellg() - FileSize2;
VertexShader.seekg(0, std::iostream::beg);
D3D12PixelShader.BytecodeLength = msl::utilities::SafeInt<SIZE_T>(FileSize.operator long long());
D3D12PixelShader.pShaderBytecode = malloc(D3D12PixelShader.BytecodeLength);
PixelShader.read(reinterpret_cast<char*>(const_cast<void*>(D3D12PixelShader.pShaderBytecode)), msl::utilities::SafeInt<long long>(D3D12PixelShader.BytecodeLength));
D3D12VertexShader.BytecodeLength = msl::utilities::SafeInt<SIZE_T>(FileSize2.operator long long());
D3D12VertexShader.pShaderBytecode = malloc(D3D12VertexShader.BytecodeLength);
VertexShader.read(reinterpret_cast<char*>(const_cast<void*>(D3D12VertexShader.pShaderBytecode)), msl::utilities::SafeInt<long long>(D3D12VertexShader.BytecodeLength));
ID3D12PipelineState* D3D12PipelineStateObject = nullptr;
static const D3D12_INPUT_ELEMENT_DESC s_inputElementDesc[2] =
{
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA , 0 }
};
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.InputLayout = { &s_inputElementDesc[0], _countof(s_inputElementDesc)};
psoDesc.pRootSignature = D3D12RootSignature;
psoDesc.PS = D3D12PixelShader;
psoDesc.VS = D3D12VertexShader;
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
psoDesc.DSVFormat = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
psoDesc.SampleMask = UINT_MAX;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
psoDesc.SampleDesc.Count = 1;
ReturnCode = D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&D3D12PipelineStateObject));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12PipelineStateObject->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Pipeline State");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12CommandQueue* D3D12CommandQueue = nullptr;
D3D12_COMMAND_QUEUE_DESC Desc = {};
Desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
Desc.NodeMask = 0;
Desc.Priority = 0;
Desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ReturnCode = D3D12Device->CreateCommandQueue(&Desc, IID_PPV_ARGS(&D3D12CommandQueue));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandQueue->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::Queue");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ID3D12GraphicsCommandList6* D3D12CommandList = nullptr;
ID3D12CommandAllocator* D3D12CommandAllocator = nullptr;
ReturnCode = D3D12Device->CreateCommandAllocator(_Type, IID_PPV_ARGS(&D3D12CommandAllocator));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandAllocator->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::Allocator");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12CommandAllocator, D3D12PipelineStateObject, IID_PPV_ARGS(&D3D12CommandList));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandList->SetName(L"SCP-Site Breach::Engine::Direct-X 12::Commands::List");
if (ReturnCode != S_OK)
{
return ReturnCode;
}
ReturnCode = D3D12CommandList->Close();
if (ReturnCode != S_OK)
{
return ReturnCode;
}
IDXGISwapChain4* DXGISwapChain = nullptr;
ID3D12DescriptorHeap* D3D12SwapChainDescriptorHeap = nullptr;
std::vector<ID3D12Resource2*> D3D12SwapChainBuffers = { nullptr, nullptr };
WNDCLASSEXW WndClass = {};
WndClass.cbSize = sizeof(WNDCLASSEXW);
WndClass.hIcon = nullptr;
WndClass.hIconSm = nullptr;
WndClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
WndClass.hInstance = GetModuleHandleW(nullptr);
WndClass.lpfnWndProc = WindowProc;
WndClass.lpszClassName = g_WndClassName.c_str();
WndClass.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
if (!RegisterClassExW(&WndClass))
{
return -1;
}
HWND m_GameWindow = CreateWindowExW(0, g_WndClassName.c_str(), L"Robo_Lab", WS_OVERLAPPED, 0, 0, 500, 500, nullptr, nullptr, GetModuleHandleW(nullptr), nullptr);
SetWindowPos(m_GameWindow, HWND_TOP, 0, 0, 1920, 1080, SWP_SHOWWINDOW);
DXGI_SWAP_CHAIN_DESC SwapChainDesc = {};
SwapChainDesc.BufferCount = 2;
SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
SwapChainDesc.BufferDesc.Height = 1080;
SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
SwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
SwapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
SwapChainDesc.BufferDesc.Width = 1920;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.OutputWindow = m_GameWindow;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
SwapChainDesc.Windowed = true;
ReturnCode = DXGIFactory->CreateSwapChain(D3D12CommandQueue, &SwapChainDesc, reinterpret_cast<IDXGISwapChain**>(&DXGISwapChain));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12_DESCRIPTOR_HEAP_DESC DescriptorHeapDesc = {};
DescriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
DescriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
DescriptorHeapDesc.NumDescriptors = 2;
ReturnCode = D3D12Device->CreateDescriptorHeap(&DescriptorHeapDesc, IID_PPV_ARGS(&D3D12SwapChainDescriptorHeap));
if (ReturnCode != S_OK)
{
return ReturnCode;
}
uint32_t RTVDescriptorSize = D3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
CD3DX12_CPU_DESCRIPTOR_HANDLE RTVDescriptorHandle(&D3D12SwapChainDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
for (size_t i = 0; i < 2; ++i)
{
DXGISwapChain->GetBuffer(i, IID_PPV_ARGS(&D3D12SwapChainBuffers.at(i)));
wchar_t BufferName[64] = { 0 };
swprintf_s(BufferName, L"SCP-Site Breach::Engine::Direct-X 12::Swap Chain Buffer[%i]", i);
ReturnCode = D3D12SwapChainBuffers.at(i)->SetName(BufferName);
if (ReturnCode != S_OK)
{
return ReturnCode;
}
D3D12Device->CreateRenderTargetView(D3D12SwapChainBuffers.at(i), nullptr, RTVDescriptorHandle);
RTVDescriptorHandle.Offset(1, RTVDescriptorSize);
}
MSG WndMessage = { nullptr };
IsRunning = true;
D3D12_RESOURCE_BARRIER BackBufferResourceBarrier = {};
BackBufferResourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
BackBufferResourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
BackBufferResourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
while (IsRunning)
{
if (PeekMessageW(&WndMessage, m_GameWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&WndMessage);
DispatchMessageW(&WndMessage);
}
if (GetWindow(m_GameWindow, 0))
{
if (D3D12Fence->GetCompletedValue() < FenceValue)
{
D3D12Fence->SetEventOnCompletion(FenceValue, FenceEvent);
WaitForSingleObject(FenceEvent, INFINITE);
}
CommandList.GetCommandAllocator()->Reset();
D3D12CommandList->Reset(CommandList.GetCommandAllocator(), Pipeline.GetPipeline());
FenceValue++;
BackBufferResourceBarrier.Transition.pResource = D3D12SwapChainBuffers.at(DXGISwapChain->GetCurrentBackBufferIndex());
BackBufferResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
BackBufferResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
D3D12CommandList->ResourceBarrier(1, &BackBufferResourceBarrier);
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(D3D12SwapChainDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12SwapChainBuffers.at(DXGISwapChain->GetCurrentBackBufferIndex()), D3D12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
D3D12CommandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
D3D12CommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
D3D12CommandList->ClearDepthStencilView(D3D12DSDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
D3D12CommandList->SetGraphicsRootSignature(D3D12CommandQueue);
BackBufferResourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
BackBufferResourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
D3D12CommandList->ResourceBarrier(1, &BackBufferResourceBarrier);
D3D12CommandList->Close();
D3D12CommandQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList**>(&D3D12CommandList));
D3D12CommandQueue->Signal(D3D12Fence, FenceValue);
DXGISwapChain->Present(0, 0);
}
}
DXGISwapChain->SetFullscreenState(FALSE, nullptr);
DXGISwapChain->Release();
D3D12SwapChainDescriptorHeap->Release();
D3D12SwapChainBuffers.at(0)->Release();
D3D12SwapChainBuffers.at(1)->Release();
D3D12CommandList->Release();
D3D12CommandAllocator->Release()
D3D12CommandQueue->Release();
D3D12PipelineStateObject->Release();
D3D12CommandQueue->Release();
CloseHandle(FenceEvent);
D3D12Fence->Release();
D3D12DSDescriptorHeap->Release();
D3D12DS->Release();
D3D12Device->Release();
#ifdef _SCPDebug
D3D12DeviceDebugInfoQueue->Release();
#endif
DXGIAdapter->Release();
DXGIFactory->Release();
D3D12DebugInterface->Release();
DXGIDebugInfoQueue->Release();
return 0;
}
Note: I converted this code from it's orginal format to this on keeping all of the settings and code. If something got messed up in the procress or converting it, it was a convertion error because this code worked fine except for the fact it was using both of my GPUs.
Edit: I forgot to mention which GPUs it was using. I have two GPUs. One is a GTX 1650, which is the one I want to use for all of my games, then I have a Intel UHD Graphics 630 (which is the GPU it wants to use) and it's my display driver. When I get the adapter and I get the description, it says it chooses my GTX, but when I look at task manager, it says it's using my display driver's 3D, and my GTX's 3D and copy. Does it have to do when I use "IDXGISwapChain::Present"?