//-------------------------------------------------------------------------- void D3D12RenderWindow::Init(D3D12Renderer& kRenderer) noexcept { if ((!m_kNode.is_attach()) && m_spTargetWindow) { D3D12_COMMAND_QUEUE_DESC kQueueDesc = {}; kQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; kQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandQueue(&kQueueDesc, IID_PPV_ARGS(&m_pkCommandQueue)), S_OK); DXGI_SWAP_CHAIN_DESC kSwapChainDesc = {}; kSwapChainDesc.BufferCount = D3D12Renderer::FRAME_COUNT; kSwapChainDesc.BufferDesc.Width = m_spTargetWindow->GetWidth(); kSwapChainDesc.BufferDesc.Height = m_spTargetWindow->GetHeight(); kSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; kSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; kSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; kSwapChainDesc.OutputWindow = (HWND)(m_spTargetWindow->GetNativeHandle()); kSwapChainDesc.SampleDesc.Count = 1; kSwapChainDesc.Windowed = TRUE; IDXGISwapChain* pkSwapChain; VE_ASSERT_GE(kRenderer.m_pkDXGIFactory->CreateSwapChain(m_pkCommandQueue, &kSwapChainDesc, &pkSwapChain), S_OK); VE_ASSERT_GE(pkSwapChain->QueryInterface(IID_PPV_ARGS(&m_pkSwapChain)), S_OK); VE_SAFE_RELEASE(pkSwapChain); VE_ASSERT(m_pkCommandQueue && m_pkSwapChain); for (uint32_t i(0); i < D3D12Renderer::FRAME_COUNT; ++i) { FrameCache& kFrame = m_akFrameCache[i]; VE_ASSERT_GE(m_pkSwapChain->GetBuffer(i, IID_PPV_ARGS(&kFrame.m_pkBufferResource)), S_OK); kFrame.m_hHandle.ptr = kRenderer.m_kRTVHeap.GetCPUStart().ptr + kRenderer.m_kRTVHeap.Alloc(); kRenderer.m_pkDevice->CreateRenderTargetView( kFrame.m_pkBufferResource, nullptr, kFrame.m_hHandle); VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&kFrame.m_pkDirectAllocator)), S_OK); VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&kFrame.m_pkBundleAllocator)), S_OK); kFrame.m_u64FenceValue = 0; VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, kFrame.m_pkDirectAllocator, nullptr, IID_PPV_ARGS(&kFrame.m_pkTestList)), S_OK); VE_ASSERT_GE(kFrame.m_pkTestList->Close(), S_OK); } m_u64FenceValue = 0; VE_ASSERT_GE(kRenderer.m_pkDevice->CreateFence(m_u64FenceValue++, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pkFence)), S_OK); m_kFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); VE_ASSERT(m_kFenceEvent); const uint64_t u64FenceToWaitFor = m_u64FenceValue++; VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, u64FenceToWaitFor), S_OK); VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(u64FenceToWaitFor, m_kFenceEvent), S_OK); WaitForSingleObject(m_kFenceEvent, INFINITE); m_u32FramePtr = m_pkSwapChain->GetCurrentBackBufferIndex(); m_u64FrameIndex = 0; m_spTargetWindow->Show(); kRenderer.m_kRenderWindowList.attach_back(m_kNode); } }
std::shared_ptr<IDXGISwapChain3> CreateSwapChain( ID3D12Device * device, ID3D12CommandQueue * commandQueue, const HWND* hWnd, DXGI_SWAP_CHAIN_DESC* swapChainDesc) { IDXGISwapChain* swapChain; IDXGISwapChain3* swapChain3; DXGI_SWAP_CHAIN_DESC defaultDesc = {}; if (!swapChainDesc) { defaultDesc.BufferCount = 2; defaultDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; defaultDesc.BufferDesc.Width = 1200; defaultDesc.BufferDesc.Height = 900; defaultDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; defaultDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; defaultDesc.OutputWindow = *hWnd; defaultDesc.SampleDesc.Count = 1; defaultDesc.Windowed = TRUE; swapChainDesc = &defaultDesc; } DirectX::ThrowIfFailed(CreateFactory()->CreateSwapChain( commandQueue, swapChainDesc, &swapChain )); swapChain->QueryInterface(IID_PPV_ARGS(&swapChain3)); swapChain->Release(); return std::shared_ptr<IDXGISwapChain3>(swapChain3, ReleaseIUnknown); }
void SwapChain::Initialize(HWND outputWindow) { Shutdown(); // We'll just use the first output for fullscreen DX12::Adapter->EnumOutputs(0, &output); if(format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) noSRGBFormat = DXGI_FORMAT_R8G8B8A8_UNORM; else if(format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) noSRGBFormat = DXGI_FORMAT_B8G8R8A8_UNORM; else noSRGBFormat = format; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = uint32(NumBackBuffers); swapChainDesc.BufferDesc.Width = width; swapChainDesc.BufferDesc.Height = height; swapChainDesc.BufferDesc.Format = noSRGBFormat; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = outputWindow; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH | DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; IDXGISwapChain* tempSwapChain = nullptr; DXCall(DX12::Factory->CreateSwapChain(DX12::GfxQueue, &swapChainDesc, &tempSwapChain)); DXCall(tempSwapChain->QueryInterface(IID_PPV_ARGS(&swapChain))); DX12::Release(tempSwapChain); backBufferIdx = swapChain->GetCurrentBackBufferIndex(); waitableObject = swapChain->GetFrameLatencyWaitableObject(); AfterReset(); }
HRESULT STDMETHODCALLTYPE CDXGISwapChainDWM::QueryInterface(REFIID riid, void **ppvObj) { return m_pSwapChain->QueryInterface(riid, ppvObj); }
HRESULT DXManager::CreateSwapChain() { HRESULT hr = S_FALSE; DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); // Set the swap chain to use double buffering. swapChainDesc.BufferCount = 2; // Set the height and width of the back buffers in the swap chain. swapChainDesc.BufferDesc.Height = m_WindowHeight; swapChainDesc.BufferDesc.Width = m_WindowWidth; // Set a regular 32-bit surface for the back buffers. swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // Set the usage of the back buffers to be render target outputs. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Set the swap effect to discard the previous buffer contents after swapping. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // Set the handle for the window to render to. swapChainDesc.OutputWindow = m_hWnd; // Set to full screen or windowed mode. if (m_FullScreen) swapChainDesc.Windowed = false; else swapChainDesc.Windowed = true; // Set the refresh rate of the back buffer. if (m_VSYNC) { swapChainDesc.BufferDesc.RefreshRate.Numerator = m_Numerator; swapChainDesc.BufferDesc.RefreshRate.Denominator = m_Denominator; } else { swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; } // Turn multisampling off. swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; // Set the scan line ordering and scaling to unspecified. swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // Don't set the advanced flags. swapChainDesc.Flags = 0; IDXGISwapChain* swapChain; ZeroMemory(&swapChain, sizeof(IDXGISwapChain)); hr = m_Factory->CreateSwapChain(m_CommandQueue, &swapChainDesc, &swapChain); if (FAILED(hr)) return hr; hr = swapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_SwapChain); if (FAILED(hr)) return hr; D3D12_DESCRIPTOR_HEAP_DESC renderTargetViewHeapDesc; ZeroMemory(&renderTargetViewHeapDesc, sizeof(D3D12_DESCRIPTOR_HEAP_DESC)); renderTargetViewHeapDesc.NumDescriptors = 2; renderTargetViewHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; renderTargetViewHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = m_Device->CreateDescriptorHeap(&renderTargetViewHeapDesc, __uuidof(ID3D12DescriptorHeap), (void**)&m_RenderTargetViewHeap); if (FAILED(hr)) return hr; D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle; ZeroMemory(&renderTargetViewHandle, sizeof(D3D12_CPU_DESCRIPTOR_HANDLE)); renderTargetViewHandle = m_RenderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); unsigned int renderTargetViewDescriptorSize = 0; renderTargetViewDescriptorSize = m_Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); hr = m_SwapChain->GetBuffer(0, __uuidof(ID3D12Resource), (void**)&m_BackBufferRenderTarget[0]); if (FAILED(hr)) return hr; m_Device->CreateRenderTargetView(m_BackBufferRenderTarget[0], NULL, renderTargetViewHandle); renderTargetViewHandle.ptr += renderTargetViewDescriptorSize; hr = m_SwapChain->GetBuffer(1, __uuidof(ID3D12Resource), (void**)&m_BackBufferRenderTarget[1]); if (FAILED(hr)) return hr; m_Device->CreateRenderTargetView(m_BackBufferRenderTarget[1], NULL, renderTargetViewHandle); m_BufferIndex = m_SwapChain->GetCurrentBackBufferIndex(); swapChain->Release(); return hr; }
void GraphicsDevice::Init(u32 screenWidth, u32 screenHeight) { #define GRAPHICSINIT_ON_FAILED(failCondition, errorMessage, ...) \ do { \ if(failCondition) \ { \ Assertf(false, errorMessage, __VA_ARGS__); \ return; \ } \ } while(0) HRESULT hr; #if RECON_DEBUG ID3D12Debug* debugInterface; hr = D3D12GetDebugInterface(__uuidof(ID3D12Debug), (void**)&debugInterface); if(Verifyf(SUCCEEDED(hr), "Failed To Create Graphics Debug Interface! Error Code: '%d'", hr)) { debugInterface->EnableDebugLayer(); } #endif // RECON_DEBUG hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&m_pDevice); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create D3D12 Device! Error Code: '%d'", hr); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; hr = m_pDevice->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&m_pCommandQueue); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create D3D12 Command Queue! Error Code: '%d'", hr); // NOTE: rasterTek does a bunch of extra stuff here before creating the swap chain // to potentially help performance? But the Directx 12 Samples don't do this. // may want to investigate in the future IDXGIFactory4* pFactory = nullptr; hr = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create DXGI Factory! Error Code: '%d'", hr); HWND hWnd = ((AppWindow_Windows*)AppEntryPoint::GetWindow())->GetWindowHandle(); DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = ms_FrameCount; swapChainDesc.BufferDesc.Width = screenWidth; swapChainDesc.BufferDesc.Height = screenHeight; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.OutputWindow = hWnd; swapChainDesc.Windowed = TRUE; // Multisampling swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; // Flags swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; IDXGISwapChain* pSwapChain = nullptr; hr = pFactory->CreateSwapChain(m_pCommandQueue, &swapChainDesc, &pSwapChain); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create Swap Chain! Error Code: '%d'", hr); hr = pSwapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_pSwapChain); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create Swap Chain 3! Error Code: '%d'", hr); // We're done with the factory pFactory->Release(); pFactory = nullptr; m_FrameIndex = m_pSwapChain->GetCurrentBackBufferIndex(); D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {}; rtvHeapDesc.NumDescriptors = ms_FrameCount; rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; hr = m_pDevice->CreateDescriptorHeap(&rtvHeapDesc, __uuidof(ID3D12DescriptorHeap), (void**)&m_pRTVHeap); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create RTV Descriptor Heap! Error Code: '%d'", hr); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_pRTVHeap->GetCPUDescriptorHandleForHeapStart(); u32 rtvHeapIncSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for(int i = 0; i < ms_FrameCount; ++i) { hr = m_pSwapChain->GetBuffer(i, __uuidof(ID3D12Resource), (void**)&m_pRenderTargets[i]); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Get RTV (%d) From Swap Chain! Error Code: '%d'", i, hr); m_pDevice->CreateRenderTargetView(m_pRenderTargets[i], nullptr, rtvHandle); rtvHandle.ptr += rtvHeapIncSize; hr = m_pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&m_pCommandAllocators[i]); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create GPU Command Allocator! Error Code: '%d'", i, hr); } // Will want to move this to another class once multithreaded rendering is supported hr = m_pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_pCommandAllocators[0], nullptr, __uuidof(ID3D12GraphicsCommandList), (void**)&m_pGraphicsCommandList); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create GPU Command Allocator! Error Code: '%d'", hr); hr = m_pGraphicsCommandList->Close(); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Close Graphics Command List! Error Code: '%d'", hr); hr = m_pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), (void**)&m_pRenderFence); GRAPHICSINIT_ON_FAILED(FAILED(hr), "Failed To Create Render Fence! Error Code: '%d'", hr); m_pRenderFenceEvent = CreateEvent(nullptr, false, false, nullptr); GRAPHICSINIT_ON_FAILED(m_pRenderFenceEvent == nullptr, "Failed To Create Render Fence Event! Error Code: '%d'", GetLastError()); #undef GRAPHICSINIT_ON_FAILED }
bool D3DClass::Initialize(int screenHeight, int screenWidth, HWND hwnd, bool vsync, bool fullscreen) { D3D_FEATURE_LEVEL featureLevel; HRESULT result; D3D12_COMMAND_QUEUE_DESC commandQueueDesc; IDXGIFactory4* factory; IDXGIAdapter* adapter; IDXGIOutput* adapterOutput; unsigned int numModes, i, numerator, denominator, renderTargetViewDescriptorSize; unsigned long long stringLength; DXGI_MODE_DESC* displayModeList; DXGI_ADAPTER_DESC adapterDesc; DXGI_SWAP_CHAIN_DESC swapChainDesc; IDXGISwapChain* swapChain; D3D12_DESCRIPTOR_HEAP_DESC renderTargetViewHeapDesc; D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle; // Store the vsync setting. m_vsync_enabled = vsync; // Set the feature level to DirectX 12.1 to enable using all the DirectX 12 features. // Note: Not all cards support full DirectX 12, this feature level may need to be reduced on some cards to 12.0. featureLevel = D3D_FEATURE_LEVEL_11_0; // Create the Direct3D 12 device. result = D3D12CreateDevice(NULL, featureLevel, __uuidof(ID3D12Device), (void**)&m_device); if (FAILED(result)) { MessageBox(hwnd, L"Could not create a DirectX 12.1 device. The default video card does not support DirectX 12.1.", L"DirectX Device Failure", MB_OK); return false; } // Initialize the description of the command queue. ZeroMemory(&commandQueueDesc, sizeof(commandQueueDesc)); // Set up the description of the command queue. commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; commandQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; commandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; commandQueueDesc.NodeMask = 0; // Create the command queue. m_device->CreateCommandQueue(&commandQueueDesc, __uuidof(ID3D12CommandQueue), (void**)&m_commandQueue); // Create a DirectX graphics interface factory. CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&factory); // Use the factory to create an adapter for the primary graphics interface (video card). factory->EnumAdapters(0, &adapter); // Enumerate the primary adapter output (monitor). adapter->EnumOutputs(0, &adapterOutput); // Get the number of modes that fit the DXGI_FORMAT_R8G8B8A8_UNORM display format for the adapter output (monitor). adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL); // Create a list to hold all the possible display modes for this monitor/video card combination. displayModeList = new DXGI_MODE_DESC[numModes]; // Now fill the display mode list structures. adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList); // Now go through all the display modes and find the one that matches the screen height and width. // When a match is found store the numerator and denominator of the refresh rate for that monitor. for (i = 0; i<numModes; i++) { if (displayModeList[i].Height == (unsigned int)screenHeight) { if (displayModeList[i].Width == (unsigned int)screenWidth) { numerator = displayModeList[i].RefreshRate.Numerator; denominator = displayModeList[i].RefreshRate.Denominator; } } } // Get the adapter (video card) description. adapter->GetDesc(&adapterDesc); // Store the dedicated video card memory in megabytes. m_videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024); // Convert the name of the video card to a character array and store it. wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128); // Release the display mode list. delete[] displayModeList; displayModeList = nullptr; // Release the adapter output. adapterOutput->Release(); adapterOutput = nullptr; // Release the adapter. adapter->Release(); adapter = nullptr; // Initialize the swap chain description. ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); // Set the swap chain to use double buffering. swapChainDesc.BufferCount = 2; // Set the height and width of the back buffers in the swap chain. swapChainDesc.BufferDesc.Height = screenHeight; swapChainDesc.BufferDesc.Width = screenWidth; // Set a regular 32-bit surface for the back buffers. swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // Set the usage of the back buffers to be render target outputs. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Set the swap effect to discard the previous buffer contents after swapping. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // Set the handle for the window to render to. swapChainDesc.OutputWindow = hwnd; // Set to full screen or windowed mode. swapChainDesc.Windowed = !fullscreen; // Set the refresh rate of the back buffer. if (m_vsync_enabled) { swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator; swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator; } else { swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; } // Turn multisampling off. swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; // Set the scan line ordering and scaling to unspecified. swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // Don't set the advanced flags. swapChainDesc.Flags = 0; // Finally create the swap chain using the swap chain description. factory->CreateSwapChain(m_commandQueue, &swapChainDesc, &swapChain); // Next upgrade the IDXGISwapChain to a IDXGISwapChain3 interface and store it in a private member variable named m_swapChain. // This will allow us to use the newer functionality such as getting the current back buffer index. swapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_swapChain); // Clear pointer to original swap chain interface since we are using version 3 instead (m_swapChain). swapChain = nullptr; // Release the factory now that the swap chain has been created. factory->Release(); factory = nullptr; // Initialize the render target view heap description for the two back buffers. ZeroMemory(&renderTargetViewHeapDesc, sizeof(renderTargetViewHeapDesc)); // Set the number of descriptors to two for our two back buffers. Also set the heap tyupe to render target views. renderTargetViewHeapDesc.NumDescriptors = 2; renderTargetViewHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; renderTargetViewHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // Create the render target view heap for the back buffers. m_device->CreateDescriptorHeap(&renderTargetViewHeapDesc, __uuidof(ID3D12DescriptorHeap), (void**)&m_renderTargetViewHeap); // Get a handle to the starting memory location in the render target view heap to identify where the render target views will be located for the two back buffers. renderTargetViewHandle = m_renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); // Get the size of the memory location for the render target view descriptors. renderTargetViewDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); // Get a pointer to the first back buffer from the swap chain. m_swapChain->GetBuffer(0, __uuidof(ID3D12Resource), (void**)&m_backBufferRenderTarget[0]); // Create a render target view for the first back buffer. m_device->CreateRenderTargetView(m_backBufferRenderTarget[0], NULL, renderTargetViewHandle); // Increment the view handle to the next descriptor location in the render target view heap. renderTargetViewHandle.ptr += renderTargetViewDescriptorSize; // Get a pointer to the second back buffer from the swap chain. m_swapChain->GetBuffer(1, __uuidof(ID3D12Resource), (void**)&m_backBufferRenderTarget[1]); // Create a render target view for the second back buffer. m_device->CreateRenderTargetView(m_backBufferRenderTarget[1], NULL, renderTargetViewHandle); // Finally get the initial index to which buffer is the current back buffer. m_bufferIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create a command allocator. m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&m_commandAllocator); // Create a fence for GPU synchronization. m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), (void**)&m_fence); // Create an event object for the fence. m_fenceEvent = CreateEvent(nullptr, false, false, nullptr); // Initialize the starting fence value. m_fenceValue = 1; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ID3DBlob* signature; ID3DBlob* error; D3D12SerializeRootSignature( &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)); //Create pipeline state, load and compiler shaders. //Note here to change D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION for debug UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; D3DReadFileToBlob(L"DefaultVS.cso", &m_vertexShader); D3DReadFileToBlob(L"DefaultHS.cso", &m_hullShader); D3DReadFileToBlob(L"DefaultDS.cso", &m_domainShader); D3DReadFileToBlob(L"DefaultPS.cso", &m_pixelShader); std::array<D3D12_INPUT_ELEMENT_DESC, 2> inputElementDescs = { D3D12_INPUT_ELEMENT_DESC{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, D3D12_INPUT_ELEMENT_DESC{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_GRAPHICS_PIPELINE_STATE_DESC pipelineDesc = {}; pipelineDesc.InputLayout = { inputElementDescs.data() , (UINT)inputElementDescs.size() }; pipelineDesc.pRootSignature = m_rootSignature; pipelineDesc.VS = { m_vertexShader->GetBufferPointer(), m_vertexShader->GetBufferSize() }; pipelineDesc.PS = { m_pixelShader->GetBufferPointer(), m_pixelShader->GetBufferSize() }; pipelineDesc.HS = { m_hullShader->GetBufferPointer(), m_hullShader->GetBufferSize() }; pipelineDesc.DS = { m_domainShader->GetBufferPointer(), m_domainShader->GetBufferSize() }; pipelineDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT_WIREFRAME); pipelineDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); pipelineDesc.DepthStencilState.DepthEnable = false; pipelineDesc.DepthStencilState.StencilEnable = false; pipelineDesc.SampleMask = UINT_MAX; pipelineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; pipelineDesc.NumRenderTargets = 1; pipelineDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; pipelineDesc.SampleDesc.Count = 1; m_device->CreateGraphicsPipelineState(&pipelineDesc, IID_PPV_ARGS(&m_pipelineState)); // Create a basic command list. m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, m_pipelineState, IID_PPV_ARGS(&m_commandList)); // Initially we need to close the command list during initialization as it is created in a recording state. m_commandList->Close(); Vertex triangleVertices[] = { { { 0.0f, 0.5f, 0.f }, { 1.f, 0.f, 0.f, 1.f } }, { { 0.5f, -0.5f, 0.f },{ 0.f, 1.f, 0.f, 1.f } }, { { -0.5f, -0.5f, 0.f },{ 0.f, 0.f, 1.f, 1.f } }, }; const UINT vertexBufferSize = sizeof(triangleVertices); m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBuffer)); UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)); memcpy(pVertexDataBegin, triangleVertices, vertexBufferSize); m_vertexBuffer->Unmap(0, nullptr); m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; m_viewport.Height = screenHeight; m_viewport.Width = screenWidth; m_viewport.MaxDepth = 1000.f; m_viewport.MinDepth = 0.1f; m_viewport.TopLeftX = 0.f; m_viewport.TopLeftY = 0.f; m_scissorRect.left = 0; m_scissorRect.right = screenWidth; m_scissorRect.top = 0; m_scissorRect.bottom = screenHeight; unsigned long long fenceToWaitFor = m_fenceValue; m_commandQueue->Signal(m_fence, fenceToWaitFor); m_fenceValue++; // Wait until the GPU is done rendering. if (m_fence->GetCompletedValue() < fenceToWaitFor) { m_fence->SetEventOnCompletion(fenceToWaitFor, m_fenceEvent); WaitForSingleObject(m_fenceEvent, INFINITE); } return true; }
//-------------------------------------------------------------------------- void VeRenderWindowD3D12::Init(VeRendererD3D12& kRenderer) noexcept { if ((!m_kNode.is_attach()) && m_spTargetWindow) { D3D12_COMMAND_QUEUE_DESC kQueueDesc = {}; kQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; kQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; if (FAILED(kRenderer.m_pkDevice->CreateCommandQueue(&kQueueDesc, IID_PPV_ARGS(&m_pkCommandQueue)))) { VE_SAFE_RELEASE(m_pkCommandQueue); VE_SAFE_RELEASE(m_pkSwapChain); return; } DXGI_SWAP_CHAIN_DESC kSwapChainDesc = {}; kSwapChainDesc.BufferCount = VeRendererD3D12::FRAME_COUNT; kSwapChainDesc.BufferDesc.Width = m_spTargetWindow->GetWidth(); kSwapChainDesc.BufferDesc.Height = m_spTargetWindow->GetHeight(); kSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; kSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; kSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; kSwapChainDesc.OutputWindow = m_spTargetWindow->GetWMInfo().win.window; kSwapChainDesc.SampleDesc.Count = 1; kSwapChainDesc.Windowed = TRUE; IDXGISwapChain* pkSwapChain; if (FAILED(kRenderer.m_pkDXGIFactory->CreateSwapChain(m_pkCommandQueue, &kSwapChainDesc, &pkSwapChain))) { VE_SAFE_RELEASE(m_pkCommandQueue); VE_SAFE_RELEASE(pkSwapChain); return; } if (FAILED(pkSwapChain->QueryInterface(IID_PPV_ARGS(&m_pkSwapChain)))) { VE_SAFE_RELEASE(m_pkCommandQueue); VE_SAFE_RELEASE(pkSwapChain); VE_SAFE_RELEASE(m_pkSwapChain); return; } else { VE_SAFE_RELEASE(pkSwapChain); } VE_ASSERT(m_pkCommandQueue && m_pkSwapChain); for (VeInt32 i(0); i < VeRendererD3D12::FRAME_COUNT; ++i) { FrameCache& kFrame = m_akFrameCache[i]; VE_ASSERT_GE(m_pkSwapChain->GetBuffer(i, IID_PPV_ARGS(&kFrame.m_pkBufferResource)), S_OK); kFrame.m_hHandle.ptr = kRenderer.m_kRTVHeap.GetCPUStart().ptr + kRenderer.m_kRTVHeap.Alloc(); kRenderer.m_pkDevice->CreateRenderTargetView( kFrame.m_pkBufferResource, nullptr, kFrame.m_hHandle); VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&kFrame.m_pkDirectAllocator)), S_OK); VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&kFrame.m_pkBundleAllocator)), S_OK); kFrame.m_u64FenceValue = 0; } m_u64FenceValue = 0; VE_ASSERT_GE(kRenderer.m_pkDevice->CreateFence(m_u64FenceValue++, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pkFence)), S_OK); m_kFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); VE_ASSERT(m_kFenceEvent); const VeUInt64 u64FenceToWaitFor = m_u64FenceValue++; VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, u64FenceToWaitFor), S_OK); VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(u64FenceToWaitFor, m_kFenceEvent), S_OK); WaitForSingleObject(m_kFenceEvent, INFINITE); m_u32FrameIndex = m_pkSwapChain->GetCurrentBackBufferIndex(); kRenderer.m_kRenderWindowList.attach_back(m_kNode); } m_kViewport.TopLeftX = 0; m_kViewport.TopLeftY = 0; m_kViewport.Width = m_spTargetWindow->GetWidth(); m_kViewport.Height = m_spTargetWindow->GetHeight(); m_kViewport.MinDepth = 0.0f; m_kViewport.MaxDepth = 1.0f; m_kScissorRect.left = 0; m_kScissorRect.right = m_spTargetWindow->GetWidth(); m_kScissorRect.top = 0; m_kScissorRect.bottom = m_spTargetWindow->GetHeight(); { m_vertexBufferView.BufferLocation = kRenderer.m_kRenderBufferList.get_tail_node()->m_Content->m_pkResource->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(VE_FLOAT3); m_vertexBufferView.SizeInBytes = kRenderer.m_kRenderBufferList.get_head_node()->m_Content->GetSize(); } }