void Direct3DManager::CreateWindowDependentResources(Vector2 screenSize, HWND windowHandle, bool vsync /*= false*/, bool fullScreen /*= false*/) { // Wait until all previous GPU work is complete. WaitForGPU(); mOutputSize = screenSize; mUseVsync = vsync; //need to handle if vsync or fullscreen changes mIsFullScreen = fullScreen; // The width and height of the swap chain must be based on the window's // natively-oriented width and height. If the window is not in the native // orientation, the dimensions must be reversed. DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation(); bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270; mOutputSize.X = swapDimensions ? screenSize.Y : screenSize.X; mOutputSize.Y = swapDimensions ? screenSize.X : screenSize.Y; if (mSwapChain != NULL) { ReleaseSwapChainDependentResources(); // If the swap chain already exists, resize it. HRESULT hr = mSwapChain->ResizeBuffers(BACK_BUFFER_COUNT, lround(mOutputSize.X), lround(mOutputSize.Y), DXGI_FORMAT_R8G8B8A8_UNORM, 0); if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) { // If the device was removed for any reason, a new device and swap chain will need to be created. mDeviceRemoved = true; // Do not continue execution of this method. DeviceResources will be destroyed and re-created. return; } else { Direct3DUtils::ThrowIfHRESULTFailed(hr); } } else { // Otherwise, create a new one using the same adapter as the existing Direct3D device. IDXGIAdapter* adapter = NULL; IDXGIOutput* adapterOutput = NULL; uint32 numDisplayModes = 0; Direct3DUtils::ThrowIfHRESULTFailed(mDXGIFactory->EnumAdapters(0, &adapter)); Direct3DUtils::ThrowIfHRESULTFailed(adapter->EnumOutputs(0, &adapterOutput)); Direct3DUtils::ThrowIfHRESULTFailed(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numDisplayModes, NULL)); DXGI_MODE_DESC *displayModeList = new DXGI_MODE_DESC[numDisplayModes]; Direct3DUtils::ThrowIfHRESULTFailed(adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numDisplayModes, displayModeList)); uint32 numerator = 0; uint32 denominator = 0; for (uint32 i = 0; i < numDisplayModes; i++) { if (displayModeList[i].Height == (uint32)mOutputSize.X) { if (displayModeList[i].Width == (uint32)mOutputSize.Y) { numerator = displayModeList[i].RefreshRate.Numerator; denominator = displayModeList[i].RefreshRate.Denominator; } } } /* DXGI_ADAPTER_DESC adapterDesc; // Get the adapter (video card) description. result = adapter->GetDesc(&adapterDesc); if(FAILED(result)) { return false; } // 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. error = wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128); if(error != 0) { return false; } */ delete[] displayModeList; displayModeList = NULL; adapterOutput->Release(); adapterOutput = NULL; adapter->Release(); adapter = NULL; DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); swapChainDesc.Width = lround(mOutputSize.X); // Match the size of the window. swapChainDesc.Height = lround(mOutputSize.Y); swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // This is the most common swap chain format. swapChainDesc.Stereo = false; swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = BACK_BUFFER_COUNT; // Use triple-buffering to minimize latency. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // All Windows Universal apps must use _FLIP_ SwapEffects swapChainDesc.Flags = 0; swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullScreenDesc = {}; ZeroMemory(&swapChainFullScreenDesc, sizeof(swapChainFullScreenDesc)); swapChainFullScreenDesc.Windowed = !mIsFullScreen; swapChainFullScreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; swapChainFullScreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; if (mUseVsync) { swapChainFullScreenDesc.RefreshRate.Numerator = numerator; swapChainFullScreenDesc.RefreshRate.Denominator = denominator; } else { swapChainFullScreenDesc.RefreshRate.Numerator = 0; swapChainFullScreenDesc.RefreshRate.Denominator = 1; } IDXGISwapChain1 *swapChain = NULL; Direct3DUtils::ThrowIfHRESULTFailed( mDXGIFactory->CreateSwapChainForHwnd( mContextManager->GetQueueManager()->GetGraphicsQueue()->GetCommandQueue(), windowHandle, &swapChainDesc, &swapChainFullScreenDesc, NULL, &swapChain ) ); Direct3DUtils::ThrowIfHRESULTFailed(swapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&mSwapChain)); } Direct3DUtils::ThrowIfHRESULTFailed(mSwapChain->SetRotation(displayRotation)); BuildSwapChainDependentResources(); // Set the 3D rendering viewport to target the entire window. mScreenViewport = { 0.0f, 0.0f, mOutputSize.X, mOutputSize.Y, 0.0f, 1.0f }; WaitForGPU(); }
bool Direct3D12Backend::initialize(const BackendParameters& params) { HRESULT hr; parameters = params; if (!initializeDirect3D12()) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: Could not load Direct3D12 dynamic library"); return false; } IDXGIFactory4* factory; hr = _CreateDXGIFactory1(IID_PPV_ARGS(&factory)); if (FAILED(hr)) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: CreateDXGIFactory1 failed (0x%X)", hr); return false; } #if defined(NUCLEUS_BUILD_DEBUG) debug.enable(); #endif hr = _D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)); if (FAILED(hr)) { logger.warning(LOG_GRAPHICS, "Direct3D12Backend::initialize: Creating WARP device"); factory->EnumWarpAdapter(IID_PPV_ARGS(&adapter)); hr = _D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)); if (FAILED(hr)) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: D3D12CreateDevice failed (0x%X)", hr); return false; } } #if defined(NUCLEUS_BUILD_DEBUG) debug.initialize(device); #endif // Create main command queue D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&queue)); if (FAILED(hr)) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: Could not create main command queue (0x%X)", hr); return false; } // Create swap chain IDXGISwapChain1* tempSwapChain; DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; swapChainDesc.Width = params.width; swapChainDesc.Height = params.height; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.Stereo = false; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 2; swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; swapChainDesc.Flags = 0; DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {}; swapChainFullscreenDesc.RefreshRate.Numerator = 60; swapChainFullscreenDesc.RefreshRate.Denominator = 1; swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; swapChainFullscreenDesc.Windowed = TRUE; #ifdef NUCLEUS_TARGET_UWP hr = factory->CreateSwapChainForCoreWindow(queue, params.window, &swapChainDesc, nullptr, &tempSwapChain); #else hr = factory->CreateSwapChainForHwnd(queue, params.hwnd, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &tempSwapChain); #endif if (FAILED(hr)) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: Could not create swap chain (0x%X)", hr); return false; } hr = tempSwapChain->QueryInterface(IID_PPV_ARGS(&swapChain)); if (FAILED(hr)) { logger.error(LOG_GRAPHICS, "Direct3D12Backend::initialize: Could not request a IDXGISwapChain3 swap chain (0x%X)", hr); return false; } // Get render target buffers from swap chain D3D12_DESCRIPTOR_HEAP_DESC swapChainRTVHeapDesc = {}; swapChainRTVHeapDesc.NumDescriptors = 2; swapChainRTVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; swapChainRTVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; device->CreateDescriptorHeap(&swapChainRTVHeapDesc, IID_PPV_ARGS(&swapChainRTVHeap)); Direct3D12ColorTarget swapChainColorTargets[2]; D3D12_CPU_DESCRIPTOR_HANDLE swapChainRTVHeapStart = swapChainRTVHeap->GetCPUDescriptorHandleForHeapStart(); unsigned int rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (UINT i = 0; i < swapChainRTVHeapDesc.NumDescriptors; i++) { swapChainColorTargets[i].handle.ptr = swapChainRTVHeapStart.ptr + (i * rtvDescriptorSize); swapChain->GetBuffer(i, IID_PPV_ARGS(&swapChainRenderBuffer[i])); device->CreateRenderTargetView(swapChainRenderBuffer[i], NULL, swapChainColorTargets[i].handle); } if (swapChain->GetCurrentBackBufferIndex() == 0) { screenBackTarget = new Direct3D12ColorTarget(swapChainColorTargets[0]); screenFrontTarget = new Direct3D12ColorTarget(swapChainColorTargets[1]); screenBackBuffer = new Direct3D12Texture(swapChainRenderBuffer[0]); screenFrontBuffer = new Direct3D12Texture(swapChainRenderBuffer[1]); } else { screenBackTarget = new Direct3D12ColorTarget(swapChainColorTargets[1]); screenFrontTarget = new Direct3D12ColorTarget(swapChainColorTargets[0]); screenBackBuffer = new Direct3D12Texture(swapChainRenderBuffer[1]); screenFrontBuffer = new Direct3D12Texture(swapChainRenderBuffer[0]); } return true; }