virtualvoidOnMouseDown(WPARAM btnState, int x, int y){} virtualvoidOnMouseUp(WPARAM btnState, int x, int y){} virtualvoidOnMouseMove(WPARAM btnState, int x, int y){} protected: voidCreateRtvAndDsvDescriptorHeaps(); boolInitDirect3D(); voidCreateCommandObjects(); voidCreateSwapChain();
boolLittleGFXInstance::Initialize(bool enableDebugLayer) { debugLayerEnabled = enableDebugLayer; UINT flags = 0; if (debugLayerEnabled) flags = DXGI_CREATE_FACTORY_DEBUG; if (SUCCEEDED(CreateDXGIFactory2(flags, IID_PPV_ARGS(&pDXGIFactory)))) { queryAllAdapters(); // If the only adapter we found is a software adapter, log error message for QA if (!adapters.size() && foundSoftwareAdapter) { assert(0 && "The only available GPU has DXGI_ADAPTER_FLAG_SOFTWARE. Early exiting"); returnfalse; } } else { assert("[D3D12 Fatal]: Create DXGIFactory2 Failed!"); returnfalse; } returntrue; }
voidLittleGFXInstance::queryAllAdapters() { IDXGIAdapter4* adapter = NULL; // Use DXGI6 interface which lets us specify gpu preference so we dont need to use NVOptimus or AMDPowerExpress for (UINT i = 0; pDXGIFactory->EnumAdapterByGpuPreference(i, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) != DXGI_ERROR_NOT_FOUND; i++) { LittleGFXAdapter newAdapter; newAdapter.pDXGIAdapter = adapter; newAdapter.instance = this; DXGI_ADAPTER_DESC3 desc = {}; adapter->GetDesc3(&desc);
//Check 4x MSAA quality support for our back buffer format. //All Direct3D 11 capable devices support 4X MSAA for all render //target formats,so we only need to check quality support. D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels; msQualityLevels.Format = mBackBufferFormat; msQualityLevels.SampleCount = 4; msQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE; msQualityLevels.NumQualityLevels = 0; //检查后会将支持的Msaa等级赋值给msQualityLevels ThrowIfFailed(md3dDevice->CheckFeatureSupport( D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msQualityLevels, sizeof(msQualityLevels) ));
//Start off in a closed state. This is because the first time we refer to the //command list we will Reset it, and it needs to be closed before calling Reset. //初次构建一个命令列表后应该先关闭它 mCommandList->Close(); }
voidLittleGFXWindow::FlushCommandQueue(){ //Advance the fence value to mark comamnds up to this fence point. mCurrentFence++;
//Add an instruction to the command queue to set a new fence point. //Because we are on the GPU timeline,the new fence point won't be set //until the GPU fnishes processing all the commands prior to this Signal() //简单来说,栅栏 ThrowIfFailed(mCommandQueue->Signal(mFence.Get(), mCurrentFence));
//Wait until the GPU has completed commands up to this fence point. //等待GPU到达当前的栅栏点 if (mFence->GetCompletedValue() < mCurrentFence) { HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
//Fire event when GPU hits current fence. ThrowIfFailed(mFence->SetEventOnCompletion(mCurrentFence, eventHandle));
//Wait until the GPU hits current fence event is fired //实际的等待 WaitForSingleObject(eventHandle, INFINITE); CloseHandle(eventHandle); } }
//Release the previous resources we will be recreating. for (int i = 0; i < SwapChainBufferCount; ++i) { mSwapChainBuffer[i].Reset(); } mDepthStencilBuffer.Reset();
//Resize the swap chain. ThrowIfFailed(mSwapChain->ResizeBuffers( SwapChainBufferCount, mClientWidth,mClientHeight, mBackBufferFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH ));
//Create the depth/stencil buffer and view D3D12_RESOURCE_DESC depthStencilDesc; depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; depthStencilDesc.Alignment = 0; depthStencilDesc.Width = mClientWidth; depthStencilDesc.Height = mClientHeight; depthStencilDesc.DepthOrArraySize = 1; depthStencilDesc.MipLevels = 1; //Coorrection 11/12/2016: SSAO chapter requires an SRV to the depth buffer to read from //the depth buffer. Therefore, because we need to create two views to the same resource: // 1. SRV format: DXGI_FORMAT_R24_UNORM_X8_TYPELESS // 2. DSV Format: DXGI_FORMAT_D24_UNORM_S8_UINT //we need to create the depth buffer resource with a typeless format. depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
//Create descriptor to mip level 0 of entire resource usin the format of the resource. D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; dsvDesc.Flags = D3D12_DSV_FLAG_NONE; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; dsvDesc.Format = mDepthStencilFormat; dsvDesc.Texture2D.MipSlice = 0; md3dDevice->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, DepthStencilView()); // Transition the resource form its initial state to be used as a depth buffer. mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mDepthStencilBuffer.Get(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_DEPTH_WRITE ));
//Shader programs typically require resources as input(constant buffers, //textures,samplers). The root signature defines the resources the shader //prorams expect. If we think of the shader programs as a function,and the input resources //as function parameters,then the root signature can be thought of as defining the //function signature.
//Add the command list to the queue for execution ID3D12CommandList* cmdsLists[] = { mCommandList.Get() }; mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
//swap the back and front buffers. ThrowIfFailed(mSwapChain->Present(0, 0)); mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
//Wait until frame commands are complete. This waiting is infficient //and is done for simplicity. Later we will show how to organize our rendering code //so we do not have to wait per frame. FlushCommandQueue(); }
//Indicate a state transition on the resource usage mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));