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"?
You might have misunderstood what the 3D queue of your integrated GPU is doing.
It's not doing the rendering work, but it is handling the entire desktop composition workload. Which GPU that happens on is determined by where your monitor's framebuffer is located on.
The Taskmanager is misleading as far as you are concerned. It shows you which engine on the GPU side is active (and it shows active time only, no load indicator!), but not from which software side queue this workload was submitted. If you take a look with GPUView instead, you will most likely see it's workload submitted by WDM, not by your process. All usage percentages you see are also wrong, as they are not adjusted for dynamic clock speeds. Your iGPU might as well be in low-power-mode and still show an 80% utilization.
Just how much the internal GPU has to work depends on your swapchain configuration. All the windowed modes naturally result in a significantly higher overhead than the full screen modes (that includes borderless full-screen!), which shows in utilization.
Good afternoon.
I am trying to write a program that will display pixels for me from the desktop, but I get an E_INVALIDARG error in the Map function.
Below I have attached my function and indicated with a comment where I got this error. I also inserted the D3D11_CREATE_DEVICE_DEBUG flag in the D3D11CreateDevice function, but it doesn't output anything. Please help.
BYTE* GetImageData()
{
if (pDupTex2D != NULL)
{
printf("Tap1\n");
/*
D3D11_TEXTURE2D_DESC description;
pDupTex2D->GetDesc(&description);
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;*/
D3D11_TEXTURE2D_DESC Desc;
//Desc.Width = 3440;
//Desc.Height = 1440;
Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
Desc.Usage = D3D11_USAGE_STAGING;
Desc.BindFlags = 0;
Desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
pDupTex2D->GetDesc(&Desc);
ID3D11Texture2D *texTemp = NULL;
HRESULT hr = pD3DDev->CreateTexture2D(&Desc, NULL, &texTemp);
std::cout << std::hex<<hr << std::endl;
if (FAILED(hr))
{
if (texTemp)
{
texTemp->Release();
texTemp = NULL;
}
return NULL;
}
printf("Tap2\n");
pCtx->CopyResource(texTemp, pDupTex2D);
D3D11_MAPPED_SUBRESOURCE mapped;
unsigned int subresource = D3D11CalcSubresource(0, 0, 0);
hr = pCtx->Map(texTemp, subresource, D3D11_MAP_READ_WRITE, 0, &mapped); // ERROR ===================================
std::cout << std::hex << hr << std::endl;
if (FAILED(hr))
{
texTemp->Release();
texTemp = NULL;
return NULL;
}
printf("Tap3\n");
unsigned char* captureData = new unsigned char[Desc.Width * Desc.Height * 4];
RtlZeroMemory(captureData, Desc.Width * Desc.Height * 4);
const int pitch = mapped.RowPitch;
unsigned char* source = static_cast<unsigned char*>(mapped.pData);
unsigned char* dest = captureData;
for (int i = 0; i < Desc.Height; i++) {
memcpy(captureData, source, Desc.Width * 4);
source += pitch;
captureData += Desc.Width * 4;
}
for (int i = 0; i < Desc.Width * Desc.Height * 4; i++) {
printf("h");
std::cout << "Pixel[%d] = %x\n" << i << dest[i] << std::endl;
}
pCtx->Unmap(texTemp, 0);
return dest;
}
else {
return NULL;
}
}
I've put together this code that takes a screenshot of the desktop and maps it for raw pixel data access, but the output is all zeros. I have no idea what i've done wrong. After looking at many examples of the Desktop Duplication Api online I don't see any differences between them and mine.
This is my method to initialize everything, and no errors are raised.
BOOL init()
{
CHECKHR(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, gFeatureLevels, gNumFeatureLevels, D3D11_SDK_VERSION, &lDevice, &FeatureLevel, &lImmediateContext))
IDXGIDevice* lDxgiDevice;
CHECKHR(lDevice->QueryInterface(IID_PPV_ARGS(&lDxgiDevice)))
IDXGIAdapter* lDxgiAdapter;
CHECKHR(lDxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&lDxgiAdapter))
lDxgiDevice->Release();
IDXGIOutput* lDxgiOutput;
CHECKHR(lDxgiAdapter->EnumOutputs(0, &lDxgiOutput))
lDxgiAdapter->Release();
CHECKHR(lDxgiOutput->GetDesc(&OutputDesc))
IDXGIOutput1* lDxgiOutput1;
CHECKHR(lDxgiOutput->QueryInterface(IID_PPV_ARGS(&lDxgiOutput1)))
lDxgiOutput->Release();
CHECKHR(lDxgiOutput1->DuplicateOutput(lDevice, &lDeskDupl))
lDxgiOutput1->Release();
lDeskDupl->GetDesc(&OutputDuplDesc);
D3D11_TEXTURE2D_DESC desc;
desc.Width = OutputDuplDesc.ModeDesc.Width;
desc.Height = OutputDuplDesc.ModeDesc.Height;
desc.Format = OutputDuplDesc.ModeDesc.Format;
desc.ArraySize = 1;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MipLevels = 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
CHECKHR(lDevice->CreateTexture2D(&desc, NULL, &lDestImage))
return TRUE;
}
the CHECKHR macro i'm using was tested by me and works, just to clarify that it is not the problem.
This is the code that I use to actually grab the frame:
int main()
{
init();
HRESULT hr;
IDXGIResource* lDesktopResource;
ID3D11Texture2D* lAcquiredDesktopImage;
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
while (true)
{
if (SUCCEEDED(lDeskDupl->AcquireNextFrame(INFINITE, &FrameInfo, &lDesktopResource)))
{
break;
}
}
hr = lDesktopResource->QueryInterface(IID_PPV_ARGS(&lAcquiredDesktopImage));
if (FAILED(hr))
{
cout << "QueryInterface failed!" << endl;
system("pause");
}
lDesktopResource->Release();
lImmediateContext->CopyResource(lDestImage, lAcquiredDesktopImage);
lAcquiredDesktopImage->Release();
lDeskDupl->ReleaseFrame();
D3D11_MAPPED_SUBRESOURCE resource;
UINT subresource = D3D11CalcSubresource(0, 0, 0);
hr = lImmediateContext->Map(lDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
if (FAILED(hr))
{
cout << "Map failed!" << endl;
system("pause");
}
BYTE* pb = (BYTE*)(resource.pData);
for (int i = 0; i < 2000000; i++)
{
cout << (int)pb[i] << endl;
}
system("pause");
return 0;
}
All that happens is 2000000 zeros get printed to the console. Is there something i'm missing or that I cant see?
First, call D3D11CreateDevice against specific adapter which output you are about to duplicate:
BOOL init()
{
IDXGIFactory* lDxgiFactory;
CHECKHR(CreateDXGIFactory1(__uuidof(IDXGIFactory), (void**)&lDxgiFactory))
IDXGIAdapter* lDxgiAdapter;
CHECKHR(lDxgiFactory->EnumAdapters(0, &lDxgiAdapter))
lDxgiFactory->Release();
CHECKHR(D3D11CreateDevice(lDxgiAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, gFeatureLevels, gNumFeatureLevels, D3D11_SDK_VERSION, &lDevice, &FeatureLevel, &lImmediateContext))
IDXGIDevice* lDxgiDevice;
CHECKHR(lDevice->QueryInterface(IID_PPV_ARGS(&lDxgiDevice)))
//IDXGIAdapter* lDxgiAdapter;
//CHECKHR(lDxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&lDxgiAdapter))
lDxgiDevice->Release();
IDXGIOutput* lDxgiOutput;
CHECKHR(lDxgiAdapter->EnumOutputs(0, &lDxgiOutput))
lDxgiAdapter->Release();
CHECKHR(lDxgiOutput->GetDesc(&OutputDesc))
IDXGIOutput1* lDxgiOutput1;
CHECKHR(lDxgiOutput->QueryInterface(IID_PPV_ARGS(&lDxgiOutput1)))
lDxgiOutput->Release();
CHECKHR(lDxgiOutput1->DuplicateOutput(lDevice, &lDeskDupl))
// ...
Then, your code is not quite accurate around AcquireNextFrame. You need to wait for actual frame and do ReleaseFrame in the loop while you are skipping.
// ...
while (true)
{
if (SUCCEEDED(lDeskDupl->AcquireNextFrame(INFINITE, &FrameInfo, &lDesktopResource)) && FrameInfo.LastPresentTime.QuadPart)
{
break;
}
lDeskDupl->ReleaseFrame();
}
// ...
I would like to access pixel buffer data from Dirty Rect after calling AcquireNextFrame from DXGI.
Here is my code to get pixel buffer data from D3D11Texture2D :
BYTE* DISPLAYMANAGER::GetImageData(ID3D11Texture2D* texture2D, D3D11_TEXTURE2D_DESC Desc)
{
if (texture2D != NULL)
{
D3D11_TEXTURE2D_DESC description;
texture2D->GetDesc(&description);
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
ID3D11Texture2D* texTemp = NULL;
HRESULT hr = m_Device->CreateTexture2D(&description, NULL, &texTemp);
if (FAILED(hr))
{
if (texTemp)
{
texTemp->Release();
texTemp = NULL;
}
return NULL;
}
m_DeviceContext->CopyResource(texTemp, texture2D);
D3D11_MAPPED_SUBRESOURCE mapped;
unsigned int subresource = D3D11CalcSubresource(0, 0, 0);
hr = m_DeviceContext->Map(texTemp, subresource, D3D11_MAP_READ_WRITE, 0, &mapped);
if (FAILED(hr))
{
texTemp->Release();
texTemp = NULL;
return NULL;
}
unsigned char *captureData = new unsigned char[Desc.Width * Desc.Height * 4];
RtlZeroMemory(captureData, Desc.Width * Desc.Height * 4);
const int pitch = mapped.RowPitch;
unsigned char *source = static_cast<unsigned char*>(mapped.pData);
unsigned char *dest = captureData;
for (int i = 0; i < Desc.Height; i++) {
memcpy(captureData, source, Desc.Width * 4);
source += pitch;
captureData += Desc.Width * 4;
}
for (int i = 0; i < Desc.Width * Desc.Height * 4; i++) {
//trace(L"Pixel[%d] = %x\n", i, dest[i]);
}
m_DeviceContext->Unmap(texTemp, 0);
return dest;
}
else
return NULL;
}
Output of dest is full of '0' value. Even mapped.pData is full of '0'. I don't know why.
Here is where I call my function GetImageData
DUPL_RETURN DISPLAYMANAGER::ProcessFrame(_In_ FRAME_DATA* Data, _Inout_ ID3D11Texture2D* SharedSurf, INT OffsetX, INT OffsetY, _In_ DXGI_OUTPUT_DESC* DeskDesc)
{
DUPL_RETURN Ret = DUPL_RETURN_SUCCESS;
// Process dirties and moves
if (Data->FrameInfo.TotalMetadataBufferSize)
{
D3D11_TEXTURE2D_DESC Desc;
Data->Frame->GetDesc(&Desc);
if (Data->MoveCount)
{
Ret = CopyMove(SharedSurf, reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(Data->MetaData), Data->MoveCount, OffsetX, OffsetY, DeskDesc, Desc.Width, Desc.Height);
if (Ret != DUPL_RETURN_SUCCESS)
{
return Ret;
}
}
if (Data->DirtyCount)
{
Ret = CopyDirty(Data->Frame, SharedSurf, reinterpret_cast<RECT*>(Data->MetaData + (Data->MoveCount * sizeof(DXGI_OUTDUPL_MOVE_RECT))), Data->DirtyCount, OffsetX, OffsetY, DeskDesc, Desc);
GetImageData(Data->Frame, Desc); //here I would like to extract the dirty rect buffer pixel (BGRA value).
}
}
return Ret;
}
Is it possible to do it ? I got this code from Microsoft Sample Desktop Duplication API. Thanks!
I am working on a face tracking program, however my getStatus() call is returning 0xcccccccc which I think is uninitialized data? Below is some of the code. I can display a color image on the screen so I am getting data ok. Can anyone give me any pointers?
IFTResult* fTrackingResult = NULL;
bool initialseFaceTracker() {
tracker = FTCreateFaceTracker();
if (!tracker) {
return false;
}
FT_CAMERA_CONFIG colorConfig = {640, 480, NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS};
FT_CAMERA_CONFIG depthConfig = {320, 240, NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS};
HRESULT hr = tracker->Initialize(&colorConfig, &depthConfig, NULL, NULL);
if ( FAILED(hr) ) {
return false;
}
hr = tracker->CreateFTResult( &fTrackingResult );
if (FAILED(hr)) {
return false;
}
IFTImage* colorFrame = FTCreateImage();
IFTImage* depthFrame = FTCreateImage();
if (!colorFrame || !depthFrame) {
return false;
}
hr = colorFrame->Attach(640, 480, &colorImageData, FTIMAGEFORMAT_UINT8_R8G8B8, 640*4);
if (FAILED(hr)) {
return false;
}
hr = depthFrame->Attach(320, 240, &depthData, FTIMAGEFORMAT_UINT16_D13P3, 320*2);
if (FAILED(hr)) {
return false;
}
sensorData.pVideoFrame = colorFrame;
sensorData.pDepthFrame = depthFrame;
sensorData.ZoomFactor = 1.0f;
sensorData.ViewOffset.x = 0;
sensorData.ViewOffset.y = 0;
return true;
}
bool updateFaceTacking() {
if(!gotFaceTracking) {
HRESULT hr = tracker->StartTracking(&sensorData, NULL, NULL, fTrackingResult);
if (SUCCEEDED(hr)){
HRESULT hr2 = fTrackingResult -> GetStatus();
if (SUCCEEDED(hr2)) {
gotFaceTracking = true;
}
}
} else {
HRESULT hr = tracker->ContinueTracking(&sensorData, NULL, fTrackingResult);
if( FAILED(fTrackingResult->GetStatus()))
gotFaceTracking = false;
}
return true;
}
you have TO place facetracker.lib and the other .dlls that come with one of the examples in your debug folder. Let me know if this helps