void Window::initializeD3D() { f = createFence(); ID3D12Device *dev = device(); if (FAILED(dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator(), Q_NULLPTR, IID_PPV_ARGS(&commandList)))) { qWarning("Failed to create command list"); return; } commandList->Close(); }
/// Overriden in derived class to initialize the graphics required for a render loop. The render loop acts as a message pump to the user clients. /// \return True if success, false if failure bool DX12Player::InitializeGraphics() { ID3D12Device* graphicsDevice = nullptr; UINT frameCount = 2; // Initialize all pipeline components necessary to render a frame. /// Invoking these calls will allow the DXGI/DX12Server plugins to be injected into our player application. // @TODO: In the future, the following commands will invoked by loaded a capture file, // initializing, and executing all captured calls. Spinning on the target frame will beat // the DX12Server's message loop, allowing communicate with GPUPerfServer. IDXGIFactory4* factory = nullptr; ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&factory))); ThrowIfFailed(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&graphicsDevice))); // Describe and create the command queue. D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; ID3D12CommandQueue* commandQueue = nullptr; ThrowIfFailed(graphicsDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue))); // Describe and create the swap chain. DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = frameCount; swapChainDesc.BufferDesc.Width = m_pPlayerWindow->GetWindowWidth(); swapChainDesc.BufferDesc.Height = m_pPlayerWindow->GetWindowHeight(); swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // The window handle must be set before being used here. swapChainDesc.OutputWindow = m_pPlayerWindow->GetWindowHandle(); swapChainDesc.SampleDesc.Count = 1; swapChainDesc.Windowed = TRUE; HRESULT res = factory->CreateSwapChain(commandQueue, &swapChainDesc, (IDXGISwapChain**)&m_swapchain); ThrowIfFailed(res); if (res != S_OK) { return false; } else { return true; } }
ID3D12Resource* RenderAPI_D3D12::GetUploadResource(UINT64 size) { if (s_D3D12Upload) { D3D12_RESOURCE_DESC desc = s_D3D12Upload->GetDesc(); if (desc.Width == size) return s_D3D12Upload; else s_D3D12Upload->Release(); } // Texture upload buffer D3D12_HEAP_PROPERTIES heapProps = {}; heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProps.CreationNodeMask = kNodeMask; heapProps.VisibleNodeMask = kNodeMask; D3D12_RESOURCE_DESC heapDesc = {}; heapDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; heapDesc.Alignment = 0; heapDesc.Width = size; heapDesc.Height = 1; heapDesc.DepthOrArraySize = 1; heapDesc.MipLevels = 1; heapDesc.Format = DXGI_FORMAT_UNKNOWN; heapDesc.SampleDesc.Count = 1; heapDesc.SampleDesc.Quality = 0; heapDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; heapDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Device* device = s_D3D12->GetDevice(); HRESULT hr = device->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &heapDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&s_D3D12Upload)); if (FAILED(hr)) { OutputDebugStringA("Failed to CreateCommittedResource.\n"); } return s_D3D12Upload; }
void RenderAPI_D3D12::CreateResources() { ID3D12Device* device = s_D3D12->GetDevice(); HRESULT hr = E_FAIL; // Command list hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&s_D3D12CmdAlloc)); if (FAILED(hr)) OutputDebugStringA("Failed to CreateCommandAllocator.\n"); hr = device->CreateCommandList(kNodeMask, D3D12_COMMAND_LIST_TYPE_DIRECT, s_D3D12CmdAlloc, nullptr, IID_PPV_ARGS(&s_D3D12CmdList)); if (FAILED(hr)) OutputDebugStringA("Failed to CreateCommandList.\n"); s_D3D12CmdList->Close(); // Fence s_D3D12FenceValue = 0; s_D3D12Event = CreateEvent(nullptr, FALSE, FALSE, nullptr); }
int BaseBuffer::Initialize(ID3D12Device& device, const GfxBufferDesc& desc) { D3D12_HEAP_PROPERTIES heapProperties = {}; heapProperties.Type = GetDx12HeapType(desc.m_heapType); heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProperties.CreationNodeMask = 1; heapProperties.VisibleNodeMask = 1; D3D12_RESOURCE_DESC resourceDesc = {}; resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; resourceDesc.Alignment = 0; resourceDesc.Width = desc.m_bufferSizeInByte; resourceDesc.Height = 1; resourceDesc.DepthOrArraySize = 1; resourceDesc.MipLevels = 1; resourceDesc.Format = DXGI_FORMAT_UNKNOWN; resourceDesc.SampleDesc.Count = 1; resourceDesc.SampleDesc.Quality = 0; resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; resourceDesc.Flags = GetDx12ResourceFlags(desc.m_resourceFlags); D3D12_RESOURCE_STATES resourceState = GetDx12ResourceStates(desc.m_resourceStates); HRESULT hr = device.CreateCommittedResource( &heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, resourceState, nullptr, IID_PPV_ARGS(&m_resource)); if(FAILED(hr)) { SI_ASSERT(0, "error device.CreateCommittedResource", _com_error(hr).ErrorMessage()); return -1; } m_bufferSizeInByte = desc.m_bufferSizeInByte; m_location = m_resource->GetGPUVirtualAddress(); if(desc.m_name) { wchar_t wName[64]; wName[0] = 0; size_t num = 0; errno_t ret = mbstowcs_s(&num, wName, desc.m_name, ArraySize(wName)); if(ret == 0) { m_resource->SetName(wName); } } return 0; }
//---------------------------------------------------------------------------// void TextureSamplerDX12::create(const ObjectName& rName, const TextureSamplerDesc& someProperties) { myProperties = someProperties; D3D12_SAMPLER_DESC desc; desc.AddressU = locResolveAddressMode(someProperties.addressModeX); desc.AddressU = locResolveAddressMode(someProperties.addressModeY); desc.AddressW = locResolveAddressMode(someProperties.addressModeZ); for (uint32 i = 0u; i < 4u; ++i) desc.BorderColor[i] = someProperties.borderColor[i]; desc.ComparisonFunc = Adapter::toNativeType(someProperties.comparisonFunc); desc.Filter = locResolveFilterMode(someProperties.minFiltering, someProperties.magFiltering); desc.MaxAnisotropy = someProperties.fMaxAnisotropy; desc.MaxLOD = someProperties.fMaxLod; desc.MinLOD = someProperties.fMinLod; desc.MipLODBias = someProperties.fLodBias; myDescriptor = RenderCoreDX12::AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); ID3D12Device* device = RenderCoreDX12::GetDevice(); device->CreateSampler(&desc, myDescriptor.myCpuHandle); }
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { MSG msg; ZeroMemory(&msg, sizeof msg); ID3D12Device* dev = nullptr; #ifdef NDEBUG try #endif { g_mainWindowHandle = setupWindow(WINDOW_WIDTH, WINDOW_HEIGHT); ShowWindow(g_mainWindowHandle, SW_SHOW); UpdateWindow(g_mainWindowHandle); D3D d3d(WINDOW_WIDTH, WINDOW_HEIGHT, g_mainWindowHandle); dev = d3d.GetDevice(); while (msg.message != WM_QUIT) { BOOL r = PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); if (r == 0) { d3d.Draw(); } else { DispatchMessage(&msg); } } } #ifdef NDEBUG catch (std::exception &e) { MessageBoxA(g_mainWindowHandle, e.what(), "Exception occuured.", MB_ICONSTOP); } #endif if (dev) dev->Release(); return static_cast<int>(msg.wParam); }
void RenderAPI_D3D12::EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) { ID3D12Device* device = s_D3D12->GetDevice(); const UINT64 kDataSize = textureWidth * textureHeight * 4; ID3D12Resource* upload = GetUploadResource(kDataSize); upload->Unmap(0, NULL); ID3D12Resource* resource = (ID3D12Resource*)textureHandle; D3D12_RESOURCE_DESC desc = resource->GetDesc(); assert(desc.Width == textureWidth); assert(desc.Height == textureHeight); D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; srcLoc.pResource = upload; srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; device->GetCopyableFootprints(&desc, 0, 1, 0, &srcLoc.PlacedFootprint, nullptr, nullptr, nullptr); D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; dstLoc.pResource = resource; dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstLoc.SubresourceIndex = 0; // We inform Unity that we expect this resource to be in D3D12_RESOURCE_STATE_COPY_DEST state, // and because we do not barrier it ourselves, we tell Unity that no changes are done on our command list. UnityGraphicsD3D12ResourceState resourceState = {}; resourceState.resource = resource; resourceState.expected = D3D12_RESOURCE_STATE_COPY_DEST; resourceState.current = D3D12_RESOURCE_STATE_COPY_DEST; // Queue data upload s_D3D12CmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); // Execute the command list s_D3D12CmdList->Close(); s_D3D12FenceValue = s_D3D12->ExecuteCommandList(s_D3D12CmdList, 1, &resourceState); }
void Draw() { mFrameCount++; int cmdIndex = mFrameCount % MaxFrameLatency; auto* cmdQueue = mCmdQueue.Get(); auto* cmdList = mCmdList.Get(); // Wait untill next queue be freed if (mFrameCount > MaxFrameLatency) { mFence->SetEventOnCompletion(mFrameCount - MaxFrameLatency, mFenceEveneHandle); DWORD wait = WaitForSingleObject(mFenceEveneHandle, 10000); if (wait != WAIT_OBJECT_0) throw runtime_error("Failed WaitForSingleObject()."); CHK(mCmdAlloc[cmdIndex]->Reset()); } CHK(cmdList->Reset(mCmdAlloc[cmdIndex].Get(), nullptr)); // Upload constant buffer { static float rot = 0.0f; rot += 1.0f; if (rot >= 360.0f) rot = 0.0f; XMMATRIX worldMat, viewMat, projMat; worldMat = XMMatrixRotationY(XMConvertToRadians(rot)); viewMat = XMMatrixLookAtLH({ 0, 1, -1.5f }, { 0, 0.5f, 0 }, { 0, 1, 0 }); projMat = XMMatrixPerspectiveFovLH(45, (float)mBufferWidth / mBufferHeight, 0.01f, 50.0f); auto mvpMat = XMMatrixTranspose(worldMat * viewMat * projMat); auto worldTransMat = XMMatrixTranspose(worldMat); // mCBUploadPtr is Write-Combine memory // Shift offset to guarantee that the pointer has not referred by executing command list. char* ptr = reinterpret_cast<char*>(mCBUploadPtr) + CB_SIZE * cmdIndex; memcpy_s(ptr, 64, &mvpMat, 64); memcpy_s(ptr + 64, 64, &worldTransMat, 64); } // Get current RTV descriptor auto descHandleRtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE descHandleRtv = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); descHandleRtv.ptr += ((mFrameCount - 1) % BUFFER_COUNT) * descHandleRtvStep; // Get current swap chain ID3D12Resource* d3dBuffer = mD3DBuffer[(mFrameCount - 1) % BUFFER_COUNT].Get(); // Get DSV auto descHandleDsv = mDescHeapDsv->GetCPUDescriptorHandleForHeapStart(); // Barrier Present -> RenderTarget setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); // Viewport & Scissor D3D12_VIEWPORT viewport = {}; viewport.Width = (float)mBufferWidth; viewport.Height = (float)mBufferHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; cmdList->RSSetViewports(1, &viewport); D3D12_RECT scissor = {}; scissor.right = (LONG)mBufferWidth; scissor.bottom = (LONG)mBufferHeight; cmdList->RSSetScissorRects(1, &scissor); // Clear DepthTexture mCmdList->ClearDepthStencilView(descHandleDsv, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Clear { float clearColor[4] = { 0.1f, 0.2f, 0.3f, 1.0f }; mCmdList->ClearRenderTargetView(descHandleRtv, clearColor, 0, nullptr); } mCmdList->OMSetRenderTargets(1, &descHandleRtv, true, &descHandleDsv); // Draw cmdList->SetGraphicsRootSignature(mRootSignature.Get()); ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav[cmdIndex].Get() }; cmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps); { cmdList->SetGraphicsRootDescriptorTable(0, mDescHeapCbvSrvUav[cmdIndex]->GetGPUDescriptorHandleForHeapStart()); cmdList->SetPipelineState(mPso.Get()); cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); cmdList->IASetVertexBuffers(0, 1, &mVBView); cmdList->IASetIndexBuffer(&mIBView); cmdList->DrawIndexedInstanced(mIndexCount, 1, 0, 0, 0); } // Barrier RenderTarget -> Present //setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); // Exec CHK(cmdList->Close()); ID3D12CommandList* const cmdLists = cmdList; //cmdQueue->ExecuteCommandLists(1, &cmdLists); CHK(cmdQueue->Signal(mFence.Get(), mFrameCount)); // Acquire RTV for D3D11 ID3D11Resource* backBuffer11 = mBackBuffer11Tex[(mFrameCount - 1) % BUFFER_COUNT].Get(); mDev11on12->AcquireWrappedResources(&backBuffer11, 1); // Draw auto* rtv11 = mBackBuffer11Rtv[(mFrameCount - 1) % BUFFER_COUNT].Get(); float color11[4] = {0.4f, 0.2f, 0.1f, 1.0f}; mDevCont11->ClearRenderTargetView(rtv11, color11); // Release RTV for D3D11 mDev11on12->ReleaseWrappedResources(&backBuffer11, 1); // Present CHK(mSwapChain->Present(1, 0)); }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf()))); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc.Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = 100; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapCbvSrvUav.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; desc.NumDescriptors = 10; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapSampler.ReleaseAndGetAddressOf()))); } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { CD3DX12_DESCRIPTOR_RANGE descRange1[2], descRange2[1]; descRange1[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, 4294967295U); descRange1[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, -1); descRange2[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0, 0, 4294967295U); CD3DX12_ROOT_PARAMETER rootParam[2]; rootParam[0].InitAsDescriptorTable(ARRAYSIZE(descRange1), descRange1); rootParam[1].InitAsDescriptorTable(ARRAYSIZE(descRange2), descRange2); ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSigDesc.NumParameters = 2; rootSigDesc.NumStaticSamplers = 0; rootSigDesc.pParameters = rootParam; rootSigDesc.pStaticSamplers = nullptr; CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"ConstantBuffer.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"ConstantBuffer.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); } D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 0; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(CCCD3DX12_DEFAULT()); psoDesc.BlendState = CD3DX12_BLEND_DESC(CCCD3DX12_DEFAULT()); psoDesc.DepthStencilState.DepthEnable = false; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); { // Read DDS file vector<char> texData(4 * 256 * 256); ifstream ifs("d3d12.dds", ios::binary); if (!ifs) throw runtime_error("Texture not found."); ifs.seekg(128, ios::beg); // Skip DDS header ifs.read(texData.data(), texData.size()); D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_B8G8R8A8_UNORM, 256, 256, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_NONE, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, //&CD3D12_RESOURCE_DESC::Buffer(texData.size()), &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mTex.ReleaseAndGetAddressOf()))); mTex->SetName(L"Texure"); D3D12_BOX box = {}; box.right = 256; box.bottom = 256; box.back = 1; CHK(mTex->WriteToSubresource(0, &box, texData.data(), 4 * 256, 4 * 256 * 256)); } D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Texture2D.MipLevels = 1; srvDesc.Texture2D.MostDetailedMip = 0; // No MIP srvDesc.Texture2D.PlaneSlice = 0; srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; mDev->CreateShaderResourceView(mTex.Get(), &srvDesc, mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart()); D3D12_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.MinLOD = -FLT_MAX; samplerDesc.MaxLOD = FLT_MAX; samplerDesc.MipLODBias = 0; samplerDesc.MaxAnisotropy = 0; samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; mDev->CreateSampler(&samplerDesc, mDescHeapSampler->GetCPUDescriptorHandleForHeapStart()); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mCB.ReleaseAndGetAddressOf()))); mCB->SetName(L"ConstantBuffer"); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = mCB->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT; // must be a multiple of 256 auto cbvSrvUavDescHandle = mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart(); auto cbvSrvUavStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); cbvSrvUavDescHandle.ptr += cbvSrvUavStep; mDev->CreateConstantBufferView( &cbvDesc, cbvSrvUavDescHandle); CHK(mCB->Map(0, nullptr, reinterpret_cast<void**>(&mCBUploadPtr))); }
void Draw() { mFrameCount++; // Upload constant buffer { static float mul = 1.0f; mul -= 0.01f; if (mul <= 0.0f) mul = 1.0f; // mCBUploadPtr is Write-Combine memory *reinterpret_cast<float*>(mCBUploadPtr) = mul; } // Get current RTV descriptor auto descHandleRtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE descHandleRtv = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); descHandleRtv.ptr += ((mFrameCount - 1) % BUFFER_COUNT) * descHandleRtvStep; // Get current swap chain ID3D12Resource* d3dBuffer = mD3DBuffer[(mFrameCount - 1) % BUFFER_COUNT].Get(); // Barrier Present -> RenderTarget setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); // Viewport & Scissor D3D12_VIEWPORT viewport = {}; viewport.Width = (float)mBufferWidth; viewport.Height = (float)mBufferHeight; mCmdList->RSSetViewports(1, &viewport); D3D12_RECT scissor = {}; scissor.right = (LONG)mBufferWidth; scissor.bottom = (LONG)mBufferHeight; mCmdList->RSSetScissorRects(1, &scissor); // Clear { auto saturate = [](float a) { return a < 0 ? 0 : a > 1 ? 1 : a; }; float clearColor[4]; static float h = 0.0f; h += 0.02f; if (h >= 1) h = 0.0f; clearColor[0] = saturate(std::abs(h * 6.0f - 3.0f) - 1.0f); clearColor[1] = saturate(2.0f - std::abs(h * 6.0f - 2.0f)); clearColor[2] = saturate(2.0f - std::abs(h * 6.0f - 4.0f)); mCmdList->ClearRenderTargetView(descHandleRtv, clearColor, 0, nullptr); } mCmdList->OMSetRenderTargets(1, &descHandleRtv, true, nullptr); // Draw { mCmdList->SetGraphicsRootSignature(mRootSignature.Get()); ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav.Get(), mDescHeapSampler.Get() }; mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps); mCmdList->SetGraphicsRootDescriptorTable(0, mDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart()); mCmdList->SetGraphicsRootDescriptorTable(1, mDescHeapSampler->GetGPUDescriptorHandleForHeapStart()); mCmdList->SetPipelineState(mPso.Get()); mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); mCmdList->DrawInstanced(4, 1, 0, 0); } // Barrier RenderTarget -> Present setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); // Exec CHK(mCmdList->Close()); ID3D12CommandList* const cmdList = mCmdList.Get(); mCmdQueue->ExecuteCommandLists(1, &cmdList); // Present CHK(mSwapChain->Present(1, 0)); // Set queue flushed event CHK(mFence->SetEventOnCompletion(mFrameCount, mFenceEveneHandle)); // Wait for queue flushed // This code would occur CPU stall! CHK(mCmdQueue->Signal(mFence.Get(), mFrameCount)); DWORD wait = WaitForSingleObject(mFenceEveneHandle, 10000); if (wait != WAIT_OBJECT_0) throw runtime_error("Failed WaitForSingleObject()."); CHK(mCmdAlloc->Reset()); CHK(mCmdList->Reset(mCmdAlloc.Get(), nullptr)); }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf()))); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc.Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; //desc.Flags = D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"Default.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"Default.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); } D3D12_INPUT_ELEMENT_DESC inputLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 1; psoDesc.InputLayout.pInputElementDescs = inputLayout; psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3DX12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3DX12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = false; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); struct float3 { float f[3]; }; float3 vbData[4] = { { -0.7f, 0.7f, 0.0f }, { 0.7f, 0.7f, 0.0f }, { -0.7f, -0.7f, 0.0f }, { 0.7f, -0.7f, 0.0f } }; unsigned short ibData[6] = { 0, 1, 2, 2, 1, 3 }; CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(vbData) + sizeof(ibData)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mVB.ReleaseAndGetAddressOf()))); mVB->SetName(L"VertexBuffer"); char* vbUploadPtr = nullptr; CHK(mVB->Map(0, nullptr, reinterpret_cast<void**>(&vbUploadPtr))); memcpy_s(vbUploadPtr, sizeof(vbData), vbData, sizeof(vbData)); memcpy_s(vbUploadPtr + sizeof(vbData), sizeof(ibData), ibData, sizeof(ibData)); mVB->Unmap(0, nullptr); mVBView.BufferLocation = mVB->GetGPUVirtualAddress(); mVBView.StrideInBytes = sizeof(float3); mVBView.SizeInBytes = sizeof(vbData); mIBView.BufferLocation = mVB->GetGPUVirtualAddress() + sizeof(vbData); mIBView.Format = DXGI_FORMAT_R16_UINT; mIBView.SizeInBytes = sizeof(ibData); }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf()))); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc.Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapDsv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = 100; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapCbvSrvUav.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; desc.NumDescriptors = 10; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapSampler.ReleaseAndGetAddressOf()))); } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { CD3DX12_DESCRIPTOR_RANGE descRange1, descRange2; descRange1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); descRange2.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); CD3DX12_ROOT_PARAMETER rootParam[2]; rootParam[0].InitAsDescriptorTable(1, &descRange1); rootParam[1].InitAsDescriptorTable(1, &descRange2); ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSigDesc.NumParameters = 2; rootSigDesc.NumStaticSamplers = 0; rootSigDesc.pParameters = rootParam; rootSigDesc.pStaticSamplers = nullptr; rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps, *vsDrawDepth, *psDrawDepth; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"DepthBuffer.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"DepthBuffer.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); CHK(D3DCompileFromFile(L"DepthBuffer.hlsl", nullptr, nullptr, "VSDrawDepth", "vs_5_0", flag, 0, &vsDrawDepth, &info)); CHK(D3DCompileFromFile(L"DepthBuffer.hlsl", nullptr, nullptr, "PSDrawDepth", "ps_5_0", flag, 0, &psDrawDepth, &info)); } D3D12_INPUT_ELEMENT_DESC inputLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 1; psoDesc.InputLayout.pInputElementDescs = inputLayout; psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(CCCD3DX12_DEFAULT()); psoDesc.BlendState = CD3DX12_BLEND_DESC(CCCD3DX12_DEFAULT()); psoDesc.DepthStencilState.DepthEnable = true; psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 0; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); psoDesc.InputLayout.NumElements = 0; psoDesc.VS.pShaderBytecode = vsDrawDepth->GetBufferPointer(); psoDesc.VS.BytecodeLength = vsDrawDepth->GetBufferSize(); psoDesc.PS.pShaderBytecode = psDrawDepth->GetBufferPointer(); psoDesc.PS.BytecodeLength = psDrawDepth->GetBufferSize(); psoDesc.DepthStencilState.DepthEnable = false; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPsoDrawDepth.ReleaseAndGetAddressOf()))); vsDrawDepth->Release(); psDrawDepth->Release(); struct float3 { float f[3]; }; float3 vbData[4] = { { -0.7f, 0.7f, 0.9f }, { 0.7f, 0.7f, 0.6f }, { -0.7f, -0.7f, 0.3f }, { 0.7f, -0.7f, 0.0f } }; unsigned short ibData[6] = { 0, 1, 2, 2, 1, 3 }; CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(vbData) + sizeof(ibData)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mVB.ReleaseAndGetAddressOf()))); mVB->SetName(L"VertexBuffer"); char* vbUploadPtr = nullptr; CHK(mVB->Map(0, nullptr, reinterpret_cast<void**>(&vbUploadPtr))); memcpy_s(vbUploadPtr, sizeof(vbData), vbData, sizeof(vbData)); memcpy_s(vbUploadPtr + sizeof(vbData), sizeof(ibData), ibData, sizeof(ibData)); mVB->Unmap(0, nullptr); mVBView.BufferLocation = mVB->GetGPUVirtualAddress(); mVBView.StrideInBytes = sizeof(float3); mVBView.SizeInBytes = sizeof(vbData); mIBView.BufferLocation = mVB->GetGPUVirtualAddress() + sizeof(vbData); mIBView.Format = DXGI_FORMAT_R16_UINT; mIBView.SizeInBytes = sizeof(ibData); auto resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_R32_TYPELESS, mBufferWidth, mBufferHeight, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); D3D12_CLEAR_VALUE dsvClearValue; dsvClearValue.Format = DXGI_FORMAT_D32_FLOAT; dsvClearValue.DepthStencil.Depth = 1.0f; dsvClearValue.DepthStencil.Stencil = 0; CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // No need to read/write by CPU D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_DEPTH_READ, &dsvClearValue, IID_PPV_ARGS(mDB.ReleaseAndGetAddressOf()))); mDB->SetName(L"DepthTexture"); D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; dsvDesc.Format = DXGI_FORMAT_D32_FLOAT; dsvDesc.Texture2D.MipSlice = 0; dsvDesc.Flags = D3D12_DSV_FLAG_NONE; mDev->CreateDepthStencilView(mDB.Get(), &dsvDesc, mDescHeapDsv->GetCPUDescriptorHandleForHeapStart()); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_R32_FLOAT; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Texture2D.MipLevels = 1; srvDesc.Texture2D.MostDetailedMip = 0; // No MIP srvDesc.Texture2D.PlaneSlice = 0; srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; mDev->CreateShaderResourceView(mDB.Get(), &srvDesc, mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart()); D3D12_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.MinLOD = -FLT_MAX; samplerDesc.MaxLOD = FLT_MAX; samplerDesc.MipLODBias = 0; samplerDesc.MaxAnisotropy = 0; samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; mDev->CreateSampler(&samplerDesc, mDescHeapSampler->GetCPUDescriptorHandleForHeapStart()); }
void Draw() { mFrameCount++; // Get current RTV descriptor auto descHandleRtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE descHandleRtv = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); descHandleRtv.ptr += ((mFrameCount - 1) % BUFFER_COUNT) * descHandleRtvStep; // Get current swap chain ID3D12Resource* d3dBuffer = mD3DBuffer[(mFrameCount - 1) % BUFFER_COUNT].Get(); // Get DSV auto descHandleDsv = mDescHeapDsv->GetCPUDescriptorHandleForHeapStart(); // Barrier SwapChain Present -> RenderTarget setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); // Barrier DepthTexture PixelShaderResource -> Depth setResourceBarrier(mCmdList.Get(), mDB.Get(), D3D12_RESOURCE_STATE_DEPTH_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE); // Viewport & Scissor D3D12_VIEWPORT viewport = {}; viewport.Width = (float)mBufferWidth; viewport.Height = (float)mBufferHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; mCmdList->RSSetViewports(1, &viewport); D3D12_RECT scissor = {}; scissor.right = (LONG)mBufferWidth; scissor.bottom = (LONG)mBufferHeight; mCmdList->RSSetScissorRects(1, &scissor); // Clear DepthTexture mCmdList->ClearDepthStencilView(descHandleDsv, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Clear { float clearColor[4] = { 0.1f, 0.2f, 0.3f, 1.0f }; mCmdList->ClearRenderTargetView(descHandleRtv, clearColor, 0, nullptr); } // Draw mCmdList->SetGraphicsRootSignature(mRootSignature.Get()); ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav.Get(), mDescHeapSampler.Get() }; mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps); { mCmdList->SetPipelineState(mPso.Get()); mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); mCmdList->IASetVertexBuffers(0, 1, &mVBView); mCmdList->IASetIndexBuffer(&mIBView); mCmdList->OMSetRenderTargets(0, nullptr, false, &descHandleDsv); mCmdList->DrawIndexedInstanced(6, 1, 0, 0, 0); } // Barrier DepthTexture Depth -> PixelShaderResource setResourceBarrier(mCmdList.Get(), mDB.Get(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_DEPTH_READ); // Draw Depth { mCmdList->SetGraphicsRootDescriptorTable(0, mDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart()); mCmdList->SetGraphicsRootDescriptorTable(1, mDescHeapSampler->GetGPUDescriptorHandleForHeapStart()); mCmdList->SetPipelineState(mPsoDrawDepth.Get()); mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); mCmdList->IASetVertexBuffers(0, 0, nullptr); mCmdList->IASetIndexBuffer(nullptr); mCmdList->OMSetRenderTargets(1, &descHandleRtv, true, nullptr); mCmdList->DrawInstanced(4, 1, 0, 0); } // Barrier RenderTarget -> Present setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); // Exec CHK(mCmdList->Close()); ID3D12CommandList* const cmdList = mCmdList.Get(); mCmdQueue->ExecuteCommandLists(1, &cmdList); // Present CHK(mSwapChain->Present(1, 0)); // Set queue flushed event CHK(mFence->SetEventOnCompletion(mFrameCount, mFenceEveneHandle)); // Wait for queue flushed // This code would occur CPU stall! CHK(mCmdQueue->Signal(mFence.Get(), mFrameCount)); DWORD wait = WaitForSingleObject(mFenceEveneHandle, 10000); if (wait != WAIT_OBJECT_0) throw runtime_error("Failed WaitForSingleObject()."); CHK(mCmdAlloc->Reset()); CHK(mCmdList->Reset(mCmdAlloc.Get(), nullptr)); }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf()))); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc.Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; //desc.Flags = D3D12_DESCRIPTOR_HEAP_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"Shader.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"Shader.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); } D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 0; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3DX12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3DX12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = false; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); }
HRESULT STDMETHODCALLTYPE DXGIXAffinityCreateSingleWindowSwapChain( IDXGISwapChain3* pSwapChain, CD3DX12AffinityCommandQueue* pQueue, CD3DX12AffinityDevice* pDevice, DXGI_SWAP_CHAIN_DESC1* pDesc, CDXGIAffinitySwapChain** ppSwapChain) { CD3DX12AffinityCommandQueue* AffinityQueue = static_cast<CD3DX12AffinityCommandQueue*>(pQueue); CD3DX12AffinityDevice* AffinityDevice = static_cast<CD3DX12AffinityDevice*>(pDevice); ID3D12Device* HostDevice = AffinityDevice->GetChildObject(0); std::vector<CDXGIAffinitySwapChain::SDeviceContext> DeviceContexts; DeviceContexts.reserve(AffinityDevice->GetDeviceCount()); for (UINT i = 0; i < AffinityDevice->GetDeviceCount(); ++i) { DeviceContexts.push_back(CDXGIAffinitySwapChain::SDeviceContext()); CDXGIAffinitySwapChain::SDeviceContext& DeviceContext = DeviceContexts.back(); DeviceContext.mDevice = AffinityDevice->GetChildObject(i); DeviceContext.mDisplayCommandQueue = AffinityQueue->GetChildObject(i); // Each device needs a command list and respective command allocator. // This list will be used for submitting resource barriers and copies from the "dummy" rendertarget. RETURN_IF_FAILED_WITH_ERROR_LOG( DeviceContext.mDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&DeviceContext.mDisplayCommandAllocator)), "Failed to create command allocator during affinity swap chain setup.", AffinityDevice); RETURN_IF_FAILED_WITH_ERROR_LOG( DeviceContext.mDevice->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, DeviceContext.mDisplayCommandAllocator, nullptr, IID_PPV_ARGS(&DeviceContext.mDisplayCommandList)), "Failed to create command list during affinity swap chain setup.", AffinityDevice); // The device at index 0 is the "host" device, it uses it's own actual render targets // and presents from this device occur in the usual fashion. // // For all devices index 1 and up, we need to create some fences and intermediate buffers // to facilitate presents. { // Create the cross-adapter copy fence, used to control access to the cross-adapter copy buffer RETURN_IF_FAILED_WITH_ERROR_LOG( DeviceContext.mDevice->CreateFence( 0, D3D12_FENCE_FLAG_SHARED | D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER, IID_PPV_ARGS(&DeviceContext.mCrossAdapterCopyFence)), "Failed to create fence during affinity swap chain setup.", AffinityDevice); std::wstring Name = std::wstring(L"CrossAdapterCopyFence") + std::to_wstring(i); RETURN_IF_FAILED(DeviceContext.mCrossAdapterCopyFence->SetName(Name.c_str())); { HANDLE CrossAdapterCopyFenceSharedHandle = nullptr; RETURN_IF_FAILED_WITH_ERROR_LOG( DeviceContext.mDevice->CreateSharedHandle( DeviceContext.mCrossAdapterCopyFence, nullptr, GENERIC_ALL, Name.c_str(), &CrossAdapterCopyFenceSharedHandle), "Failed to create shared handle to cross adapter copy fence during affinity swap chain setup.", AffinityDevice); RETURN_IF_FAILED_WITH_ERROR_LOG( HostDevice->OpenSharedHandle(CrossAdapterCopyFenceSharedHandle, IID_PPV_ARGS(&DeviceContext.mCrossAdapterCopyFenceOnHost)), "Failed to open shared handle to cross adapter copy fence during affinity swap chain setup.", AffinityDevice); Name = std::wstring(L"CrossAdapterCopyFenceOnHost") + std::to_wstring(i); RETURN_IF_FAILED(DeviceContext.mCrossAdapterCopyFenceOnHost->SetName(L"CrossAdapterCopyFenceOnHost")); } // Create the "dummy" render targets and cross-adapter copy buffers. // For a swap chain with (n) back buffers, we create (n) render targets and (n) cross-adapter copy buffers. DeviceContext.mRenderTargets.reserve(pDesc->BufferCount); DeviceContext.mCrossAdapterCopyBuffers.reserve(pDesc->BufferCount); RETURN_IF_FAILED(CDXGIAffinitySwapChain::CreateDummyRenderTargetsAndCrossAdapterCopyBuffers( i, AffinityDevice, HostDevice, DeviceContext, pDesc->Width, pDesc->Height, pDesc->Format, pDesc->BufferCount )); } } pSwapChain->AddRef(); CDXGIAffinitySwapChain* AffinityChain = new CDXGIAffinitySwapChain(AffinityDevice, AffinityQueue, &pSwapChain, 1); if (AffinityDevice->GetAffinityMode() == EAffinityMode::LDA) { AffinityChain->mMode = EAffinitySwapChainMode::LDA; } else { AffinityChain->mMode = EAffinitySwapChainMode::SingleWindow; } AffinityChain->mDeviceContexts = DeviceContexts; AffinityChain->mNumBackBuffers = pDesc->BufferCount; AffinityChain->mHostDevice = HostDevice; *ppSwapChain = AffinityChain; return S_OK; }
GPA_Status GPA_IMP_GetHWInfo(void* pContext, GPA_HWInfo* pHwInfo) { GPA_Status result = GPA_STATUS_OK; if (nullptr == pContext) { GPA_LogError("Parameter 'pContext' is NULL."); result = GPA_STATUS_ERROR_NULL_POINTER; } else if (nullptr == pHwInfo) { GPA_LogError("Parameter 'pHwInfo' is NULL."); result = GPA_STATUS_ERROR_NULL_POINTER; } else { IUnknown* pUnknown = static_cast<IUnknown*>(pContext); ID3D12GraphicsCommandList* pCommandList = nullptr; HRESULT hr = pUnknown->QueryInterface(__uuidof(ID3D12GraphicsCommandList), reinterpret_cast<void**>(&pCommandList)); if (S_OK != hr) { GPA_LogError("Failed to get command list from context"); result = GPA_STATUS_ERROR_FAILED; } else { ID3D12Device* pDevice; hr = pCommandList->GetDevice(__uuidof(ID3D12Device), reinterpret_cast<void**>(&pDevice)); if (S_OK != hr) { GPA_LogError("Failed to get device from command list"); result = GPA_STATUS_ERROR_FAILED; } else { DXGI_ADAPTER_DESC adapterDesc; result = DX12GetAdapterDesc(pDevice, adapterDesc); if (GPA_STATUS_OK != result) { GPA_LogError("Could not get adapter description, hardware cannot be supported."); result = GPA_STATUS_ERROR_FAILED; } else { //get Time stamp frequency gpa_uint64 freq = 0ull; if (nullptr == g_pCurrentContext) { GPA_LogError("g_pCurrentContext is NULL."); result = GPA_STATUS_ERROR_NULL_POINTER; return result; } GetCurrentContext()->SetCommandList(pCommandList); result = GetCurrentContext()->GetTimestampFrequency(freq); if (GPA_STATUS_OK != result) { GPA_LogError("GetTimestampFrequency() failed."); } else { // For now it is assumed that DX12 MGPU support is exposed to the app // and the app always opens the device on the correct GPU. // In case where MGPU support hides the GPU from the app, then // we will need to use DX12 MGPU extension (and possibly ADL util) // to get the correct HW info pHwInfo->SetVendorID(adapterDesc.VendorId); // TODO: To enable running on WARP driver, fake a Bonaire HW ID if the device is the WARP device if (0x8c == adapterDesc.DeviceId && AMD_VENDOR_ID == adapterDesc.VendorId) { pHwInfo->SetDeviceID(0x665C); pHwInfo->SetRevisionID(0); } else { pHwInfo->SetVendorID(adapterDesc.VendorId); pHwInfo->SetDeviceID(adapterDesc.DeviceId); pHwInfo->SetRevisionID(adapterDesc.Revision); } std::wstring adapterNameW(adapterDesc.Description); std::string adapterName(adapterNameW.begin(), adapterNameW.end()); pHwInfo->SetDeviceName(adapterName.c_str()); GDT_HW_GENERATION hwGen = GDT_HW_GENERATION_NONE; if (NVIDIA_VENDOR_ID == adapterDesc.VendorId) { hwGen = GDT_HW_GENERATION_NVIDIA; } else if (INTEL_VENDOR_ID == adapterDesc.VendorId) { hwGen = GDT_HW_GENERATION_INTEL; } else if (AMD_VENDOR_ID == adapterDesc.VendorId) { AMDTDeviceInfoUtils::Instance()->GetHardwareGeneration(adapterDesc.DeviceId, hwGen); } pHwInfo->SetHWGeneration(hwGen); pHwInfo->SetTimeStampFrequency(freq); } } pDevice->Release(); } pCommandList->Release(); } } return result; }
GPA_Status GPA_IMP_VerifyHWSupport(void* pContext, GPA_HWInfo* pHwInfo) { GPA_Status result = GPA_STATUS_OK; if ((nullptr == pContext) || (nullptr == pHwInfo)) { result = GPA_STATUS_ERROR_FAILED; } else { IUnknown* pUnknown = static_cast<IUnknown*>(pContext); ID3D12GraphicsCommandList* pCommandList = nullptr; HRESULT hr = pUnknown->QueryInterface(__uuidof(ID3D12GraphicsCommandList), reinterpret_cast<void**>(&pCommandList)); if (S_OK != hr) { GPA_LogError("Failed to get command list from context"); result = GPA_STATUS_ERROR_FAILED; } else { ID3D12Device* pDevice; hr = pCommandList->GetDevice(__uuidof(ID3D12Device), reinterpret_cast<void**>(&pDevice)); if (S_OK != hr) { GPA_LogError("Failed to get D3D12 device"); result = GPA_STATUS_ERROR_FAILED; } else { D3D12_FEATURE_DATA_FEATURE_LEVELS featureLevels; static const D3D_FEATURE_LEVEL requestedFeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, }; featureLevels.NumFeatureLevels = (sizeof(requestedFeatureLevels) / sizeof(D3D_FEATURE_LEVEL)); featureLevels.pFeatureLevelsRequested = requestedFeatureLevels; featureLevels.MaxSupportedFeatureLevel = D3D_FEATURE_LEVEL_11_1; hr = pDevice->CheckFeatureSupport( D3D12_FEATURE_FEATURE_LEVELS, &featureLevels, sizeof(featureLevels)); if (S_OK != hr) { GPA_LogError("Failed to get D3D12 device feature levels"); result = GPA_STATUS_ERROR_FAILED; } else { if (D3D_FEATURE_LEVEL_11_0 > featureLevels.MaxSupportedFeatureLevel) { result = GPA_STATUS_ERROR_HARDWARE_NOT_SUPPORTED; } else { // TODO Once DX12 performance extension is available, check // it's possible to create a HW counter } } pDevice->Release(); } pCommandList->Release(); } } return result; } // end of GPA_IMP_VerifyHwSupport
int BaseGraphicsState::Initialize(ID3D12Device& device, const GfxGraphicsStateDesc& desc) { D3D12_INPUT_ELEMENT_DESC elements[32]; SI_ASSERT(desc.m_inputElementCount < ArraySize(elements)); uint32_t elementCont = SI::Min((uint32_t)desc.m_inputElementCount, (uint32_t)ArraySize(elements)); for(uint32_t e=0; e<elementCont; ++e) { D3D12_INPUT_ELEMENT_DESC& outElem = elements[e]; const GfxInputElement& inElem = desc.m_inputElements[e]; outElem.SemanticName = inElem.m_semanticsName; outElem.SemanticIndex = inElem.m_semanticsId; outElem.Format = SI::GetDx12Format(inElem.m_format); outElem.InputSlot = inElem.m_inputSlot; outElem.AlignedByteOffset = inElem.m_alignedByteOffset; outElem.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; outElem.InstanceDataStepRate = 0; } const BaseShader* vertexShader = desc.m_vertexShader->GetBaseShader(); const BaseShader* pixelShader = desc.m_pixelShader->GetBaseShader(); D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { elements, elementCont }; psoDesc.pRootSignature = desc.m_rootSignature->GetBaseRootSignature()->GetComPtrRootSignature().Get(); psoDesc.VS.pShaderBytecode = vertexShader? vertexShader->GetBinary() : nullptr; psoDesc.VS.BytecodeLength = vertexShader? vertexShader->GetBinarySize() : 0; psoDesc.PS.pShaderBytecode = pixelShader? pixelShader->GetBinary() : nullptr; psoDesc.PS.BytecodeLength = pixelShader? pixelShader->GetBinarySize() : 0; psoDesc.RasterizerState.FillMode = GetDx12FillMode(desc.m_fillMode); psoDesc.RasterizerState.CullMode = GetDx12CullMode(desc.m_cullMode); psoDesc.RasterizerState.FrontCounterClockwise = desc.m_frontCounterClockwise? TRUE : FALSE; psoDesc.RasterizerState.DepthBias = desc.m_depthBias; psoDesc.RasterizerState.DepthBiasClamp = desc.m_depthBiasClamp; psoDesc.RasterizerState.SlopeScaledDepthBias = desc.m_slopeScaledDepthBias; psoDesc.RasterizerState.DepthClipEnable = TRUE; psoDesc.RasterizerState.MultisampleEnable = FALSE; psoDesc.RasterizerState.AntialiasedLineEnable = FALSE; psoDesc.RasterizerState.ForcedSampleCount = 0; psoDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = GetDx12PrimitiveTopologyType(desc.m_primitiveTopologyType); psoDesc.SampleDesc.Count = 1; psoDesc.NumRenderTargets = desc.m_renderTargetCount; psoDesc.BlendState.AlphaToCoverageEnable = FALSE; psoDesc.BlendState.IndependentBlendEnable = FALSE; psoDesc.DepthStencilState.DepthEnable = desc.m_depthEnable? TRUE : FALSE; psoDesc.DepthStencilState.StencilEnable = desc.m_stencilEnable? TRUE : FALSE; if(psoDesc.DepthStencilState.DepthEnable) { psoDesc.DepthStencilState.DepthWriteMask = GetDx12DepthWriteMask(desc.m_depthWriteMask); psoDesc.DepthStencilState.DepthFunc = GetDx12ComparisonFunc(desc.m_depthFunc); } SI_ASSERT(desc.m_renderTargetCount <= D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT); UINT blendRtCount = psoDesc.BlendState.IndependentBlendEnable? psoDesc.NumRenderTargets : 1; for (UINT rt = 0; rt<blendRtCount; ++rt) { D3D12_RENDER_TARGET_BLEND_DESC& outBlend = psoDesc.BlendState.RenderTarget[rt]; const GfxRenderTargetBlendDesc& inBlend = desc.m_rtvBlend[rt]; outBlend.BlendEnable = inBlend.m_blendEnable? TRUE : FALSE; outBlend.LogicOpEnable = inBlend.m_logicOpEnable? TRUE : FALSE; outBlend.SrcBlend = GetDx12Blend(inBlend.m_srcBlend); outBlend.DestBlend = GetDx12Blend(inBlend.m_destBlend); outBlend.BlendOp = GetDx12BlendOp(inBlend.m_blendOp); outBlend.SrcBlendAlpha = GetDx12Blend(inBlend.m_srcBlendAlpha); outBlend.DestBlendAlpha = GetDx12Blend(inBlend.m_destBlendAlpha); outBlend.BlendOpAlpha = GetDx12BlendOp(inBlend.m_blendOpAlpha); outBlend.LogicOp = GetDx12LogicOp(inBlend.m_logicOp); outBlend.RenderTargetWriteMask = GetDx12RenderTargetWriteMask(inBlend.m_rtWriteMask); } for (UINT rt = 0; rt<psoDesc.NumRenderTargets; ++rt) { psoDesc.RTVFormats[rt] = GetDx12Format(desc.m_rtvFormats[rt]); } psoDesc.DSVFormat = GetDx12Format(desc.m_dsvFormat); HRESULT hr = device.CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState)); if(FAILED(hr)) { SI_ASSERT(0); return -1; } if(desc.m_name) { wchar_t wName[64]; wName[0] = 0; size_t num = 0; errno_t ret = mbstowcs_s(&num, wName, desc.m_name, ArraySize(wName)); if(ret == 0) { m_pipelineState->SetName(wName); } } return 0; }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(mCmdAlloc.ReleaseAndGetAddressOf()))); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc.Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapDsv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = 100; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapCbvSrvUav.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; desc.NumDescriptors = 100; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapSampler.ReleaseAndGetAddressOf()))); } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { CD3DX12_DESCRIPTOR_RANGE descRange1[2]; descRange1[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); descRange1[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); CD3DX12_DESCRIPTOR_RANGE descRange2[1]; descRange2[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0); CD3DX12_ROOT_PARAMETER rootParam[2]; rootParam[0].InitAsDescriptorTable(ARRAYSIZE(descRange1), descRange1); rootParam[1].InitAsDescriptorTable(ARRAYSIZE(descRange2), descRange2, D3D12_SHADER_VISIBILITY_PIXEL); ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSigDesc.NumParameters = ARRAYSIZE(rootParam); rootSigDesc.NumStaticSamplers = 0; rootSigDesc.pParameters = rootParam; rootSigDesc.pStaticSamplers = nullptr; rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"MeshTex.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"MeshTex.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); } D3D12_INPUT_ELEMENT_DESC inputLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 3; psoDesc.InputLayout.pInputElementDescs = inputLayout; psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3DX12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3DX12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = true; psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); WaveFrontReader<uint16_t> mesh; CHK(mesh.Load(L"teapot_tex2.obj")); mIndexCount = static_cast<UINT>(mesh.indices.size()); mVBIndexOffset = static_cast<UINT>(sizeof(mesh.vertices[0]) * mesh.vertices.size()); UINT IBSize = static_cast<UINT>(sizeof(mesh.indices[0]) * mIndexCount); void* vbData = mesh.vertices.data(); void* ibData = mesh.indices.data(); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(mVBIndexOffset + IBSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mVB.ReleaseAndGetAddressOf()))); mVB->SetName(L"VertexBuffer"); char* vbUploadPtr = nullptr; CHK(mVB->Map(0, nullptr, reinterpret_cast<void**>(&vbUploadPtr))); memcpy_s(vbUploadPtr, mVBIndexOffset, vbData, mVBIndexOffset); memcpy_s(vbUploadPtr + mVBIndexOffset, IBSize, ibData, IBSize); mVB->Unmap(0, nullptr); mVBView.BufferLocation = mVB->GetGPUVirtualAddress(); mVBView.StrideInBytes = sizeof(mesh.vertices[0]); mVBView.SizeInBytes = mVBIndexOffset; mIBView.BufferLocation = mVB->GetGPUVirtualAddress() + mVBIndexOffset; mIBView.Format = DXGI_FORMAT_R16_UINT; mIBView.SizeInBytes = IBSize; auto resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_R32_TYPELESS, mBufferWidth, mBufferHeight, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); D3D12_CLEAR_VALUE dsvClearValue; dsvClearValue.Format = DXGI_FORMAT_D32_FLOAT; dsvClearValue.DepthStencil.Depth = 1.0f; dsvClearValue.DepthStencil.Stencil = 0; CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // No need to read/write by CPU D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &dsvClearValue, IID_PPV_ARGS(mDB.ReleaseAndGetAddressOf()))); mDB->SetName(L"DepthTexture"); D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; dsvDesc.Format = DXGI_FORMAT_D32_FLOAT; dsvDesc.Texture2D.MipSlice = 0; dsvDesc.Flags = D3D12_DSV_FLAG_NONE; mDev->CreateDepthStencilView(mDB.Get(), &dsvDesc, mDescHeapDsv->GetCPUDescriptorHandleForHeapStart()); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mCB.ReleaseAndGetAddressOf()))); mCB->SetName(L"ConstantBuffer"); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = mCB->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT; // must be a multiple of 256 mDev->CreateConstantBufferView( &cbvDesc, mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart()); CHK(mCB->Map(0, nullptr, reinterpret_cast<void**>(&mCBUploadPtr))); { // Read DDS file vector<char> texData(4 * 256 * 256); ifstream ifs("cat.dds", ios::binary); if (!ifs) throw runtime_error("Texture not found."); ifs.seekg(128, ios::beg); // Skip DDS header ifs.read(texData.data(), texData.size()); resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_B8G8R8A8_UNORM, 256, 256, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_NONE, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mTex.ReleaseAndGetAddressOf()))); mTex->SetName(L"Texure"); D3D12_BOX box = {}; box.right = 256; box.bottom = 256; box.back = 1; CHK(mTex->WriteToSubresource(0, &box, texData.data(), 4 * 256, 4 * 256 * 256)); } D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Texture2D.MipLevels = 1; srvDesc.Texture2D.MostDetailedMip = 0; // No MIP srvDesc.Texture2D.PlaneSlice = 0; srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; auto cbvSrcUavDescHandle = mDescHeapCbvSrvUav->GetCPUDescriptorHandleForHeapStart(); auto cbvSrvUavDescStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); cbvSrcUavDescHandle.ptr += cbvSrvUavDescStep; mDev->CreateShaderResourceView(mTex.Get(), &srvDesc, cbvSrcUavDescHandle); D3D12_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; samplerDesc.MinLOD = -FLT_MAX; samplerDesc.MaxLOD = FLT_MAX; samplerDesc.MipLODBias = 0; samplerDesc.MaxAnisotropy = 0; samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; mDev->CreateSampler(&samplerDesc, mDescHeapSampler->GetCPUDescriptorHandleForHeapStart()); }
D3D(int width, int height, HWND hWnd) : mBufferWidth(width), mBufferHeight(height), mDev(nullptr) { { #if _DEBUG CHK(CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #else CHK(CreateDXGIFactory2(0, IID_PPV_ARGS(mDxgiFactory.ReleaseAndGetAddressOf()))); #endif /* _DEBUG */ } #if _DEBUG ID3D12Debug* debug = nullptr; D3D12GetDebugInterface(IID_PPV_ARGS(&debug)); if (debug) { debug->EnableDebugLayer(); debug->Release(); debug = nullptr; } #endif /* _DEBUG */ ID3D12Device* dev; CHK(D3D12CreateDevice( nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&dev))); mDev = dev; for (auto& a : mCmdAlloc) { CHK(mDev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(a.ReleaseAndGetAddressOf()))); } D3D12_COMMAND_QUEUE_DESC queueDesc = {}; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; CHK(mDev->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(mCmdQueue.ReleaseAndGetAddressOf()))); DXGI_SWAP_CHAIN_DESC1 scDesc = {}; scDesc.Width = width; scDesc.Height = height; scDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scDesc.SampleDesc.Count = 1; scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scDesc.BufferCount = BUFFER_COUNT; scDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; CHK(mDxgiFactory->CreateSwapChainForHwnd(mCmdQueue.Get(), hWnd, &scDesc, nullptr, nullptr, mSwapChain.ReleaseAndGetAddressOf())); CHK(mDev->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAlloc[0].Get(), nullptr, IID_PPV_ARGS(mCmdList.ReleaseAndGetAddressOf()))); mCmdList->Close(); CHK(mDev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(mFence.ReleaseAndGetAddressOf()))); mFenceEveneHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr); for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mSwapChain->GetBuffer(i, IID_PPV_ARGS(mD3DBuffer[i].ReleaseAndGetAddressOf()))); mD3DBuffer[i]->SetName(L"SwapChain_Buffer"); } { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapRtv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; desc.NumDescriptors = 10; desc.NodeMask = 0; CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(mDescHeapDsv.ReleaseAndGetAddressOf()))); desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = 100; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.NodeMask = 0; for (auto& c : mDescHeapCbvSrvUav) { CHK(mDev->CreateDescriptorHeap(&desc, IID_PPV_ARGS(c.ReleaseAndGetAddressOf()))); } } auto rtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (auto i = 0u; i < BUFFER_COUNT; i++) { auto d = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); d.ptr += i * rtvStep; mDev->CreateRenderTargetView(mD3DBuffer[i].Get(), nullptr, d); } { CD3DX12_DESCRIPTOR_RANGE descRange1[1]; descRange1[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); CD3DX12_ROOT_PARAMETER rootParam[1]; rootParam[0].InitAsDescriptorTable(ARRAYSIZE(descRange1), descRange1); ID3D10Blob *sig, *info; auto rootSigDesc = D3D12_ROOT_SIGNATURE_DESC(); rootSigDesc.NumParameters = 1; rootSigDesc.NumStaticSamplers = 0; rootSigDesc.pParameters = rootParam; rootSigDesc.pStaticSamplers = nullptr; rootSigDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; CHK(D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &sig, &info)); mDev->CreateRootSignature( 0, sig->GetBufferPointer(), sig->GetBufferSize(), IID_PPV_ARGS(mRootSignature.ReleaseAndGetAddressOf())); sig->Release(); } ID3D10Blob *vs, *ps; { ID3D10Blob *info; UINT flag = 0; #if _DEBUG flag |= D3DCOMPILE_DEBUG; #endif /* _DEBUG */ CHK(D3DCompileFromFile(L"../Mesh/Mesh.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", flag, 0, &vs, &info)); CHK(D3DCompileFromFile(L"../Mesh/Mesh.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", flag, 0, &ps, &info)); } D3D12_INPUT_ELEMENT_DESC inputLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.InputLayout.NumElements = 3; psoDesc.InputLayout.pInputElementDescs = inputLayout; psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; psoDesc.pRootSignature = mRootSignature.Get(); psoDesc.VS.pShaderBytecode = vs->GetBufferPointer(); psoDesc.VS.BytecodeLength = vs->GetBufferSize(); psoDesc.PS.pShaderBytecode = ps->GetBufferPointer(); psoDesc.PS.BytecodeLength = ps->GetBufferSize(); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3DX12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3DX12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = true; psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; psoDesc.DepthStencilState.StencilEnable = false; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; CHK(mDev->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(mPso.ReleaseAndGetAddressOf()))); vs->Release(); ps->Release(); WaveFrontReader<uint16_t> mesh; CHK(mesh.Load(L"../Mesh/teapot.obj")); mIndexCount = static_cast<UINT>(mesh.indices.size()); mVBIndexOffset = static_cast<UINT>(sizeof(mesh.vertices[0]) * mesh.vertices.size()); UINT IBSize = static_cast<UINT>(sizeof(mesh.indices[0]) * mIndexCount); void* vbData = mesh.vertices.data(); void* ibData = mesh.indices.data(); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(mVBIndexOffset + IBSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mVB.ReleaseAndGetAddressOf()))); mVB->SetName(L"VertexBuffer"); char* vbUploadPtr = nullptr; CHK(mVB->Map(0, nullptr, reinterpret_cast<void**>(&vbUploadPtr))); memcpy_s(vbUploadPtr, mVBIndexOffset, vbData, mVBIndexOffset); memcpy_s(vbUploadPtr + mVBIndexOffset, IBSize, ibData, IBSize); mVB->Unmap(0, nullptr); mVBView.BufferLocation = mVB->GetGPUVirtualAddress(); mVBView.StrideInBytes = sizeof(mesh.vertices[0]); mVBView.SizeInBytes = mVBIndexOffset; mIBView.BufferLocation = mVB->GetGPUVirtualAddress() + mVBIndexOffset; mIBView.Format = DXGI_FORMAT_R16_UINT; mIBView.SizeInBytes = IBSize; auto resourceDesc = CD3DX12_RESOURCE_DESC::Tex2D( DXGI_FORMAT_R32_TYPELESS, mBufferWidth, mBufferHeight, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0); D3D12_CLEAR_VALUE dsvClearValue; dsvClearValue.Format = DXGI_FORMAT_D32_FLOAT; dsvClearValue.DepthStencil.Depth = 1.0f; dsvClearValue.DepthStencil.Stencil = 0; CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // No need to read/write by CPU D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &dsvClearValue, IID_PPV_ARGS(mDB.ReleaseAndGetAddressOf()))); mDB->SetName(L"DepthTexture"); D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; dsvDesc.Format = DXGI_FORMAT_D32_FLOAT; dsvDesc.Texture2D.MipSlice = 0; dsvDesc.Flags = D3D12_DSV_FLAG_NONE; mDev->CreateDepthStencilView(mDB.Get(), &dsvDesc, mDescHeapDsv->GetCPUDescriptorHandleForHeapStart()); #define CB_SIZE 256 UINT cbSize = CB_SIZE; assert((cbSize % D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT) == 0); CHK(mDev->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(cbSize * MaxFrameLatency), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(mCB.ReleaseAndGetAddressOf()))); mCB->SetName(L"ConstantBuffer"); for (auto i = 0u; i < MaxFrameLatency; ++i) { D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = mCB->GetGPUVirtualAddress() + i * cbSize; cbvDesc.SizeInBytes = cbSize; mDev->CreateConstantBufferView( &cbvDesc, mDescHeapCbvSrvUav[i]->GetCPUDescriptorHandleForHeapStart()); } CHK(mCB->Map(0, nullptr, reinterpret_cast<void**>(&mCBUploadPtr))); // Create D3D11 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; auto featureLevel = D3D_FEATURE_LEVEL_11_0; auto cmdQueue = static_cast<IUnknown*>(mCmdQueue.Get()); #if _DEBUG flags |= D3D11_CREATE_DEVICE_DEBUG; #endif /* _DEBUG */ CHK(D3D11On12CreateDevice( static_cast<IUnknown*>(mDev), flags, &featureLevel, 1, &cmdQueue, 1, 0, mDev11.ReleaseAndGetAddressOf(), mDevCont11.ReleaseAndGetAddressOf(), nullptr)); CHK(mDev11.As(&mDev11on12)); D3D11_RESOURCE_FLAGS backBuffer11Flags = {}; backBuffer11Flags.BindFlags = D3D11_BIND_RENDER_TARGET; for (int i = 0; i < BUFFER_COUNT; i++) { CHK(mDev11on12->CreateWrappedResource( mD3DBuffer[i].Get(), &backBuffer11Flags, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET, IID_PPV_ARGS(&mBackBuffer11Tex[i]))); D3D11_TEXTURE2D_DESC texDesc; mBackBuffer11Tex[i]->GetDesc(&texDesc); D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; rtvDesc.Format = texDesc.Format; rtvDesc.Texture2D.MipSlice = 0; CHK(mDev11->CreateRenderTargetView( mBackBuffer11Tex[i].Get(), &rtvDesc, mBackBuffer11Rtv[i].ReleaseAndGetAddressOf())); } }
void Draw() { mFrameCount++; // Upload constant buffer { static float rot = 0.0f; rot += 1.0f; if (rot >= 360.0f) rot = 0.0f; XMMATRIX worldMat, viewMat, projMat; worldMat = XMMatrixRotationY(XMConvertToRadians(rot)); viewMat = XMMatrixLookAtLH({ 0, 1, -1.5f }, { 0, 0.5f, 0 }, { 0, 1, 0 }); projMat = XMMatrixPerspectiveFovLH(45, (float)mBufferWidth / mBufferHeight, 0.01f, 50.0f); auto mvpMat = XMMatrixTranspose(worldMat * viewMat * projMat); auto worldTransMat = XMMatrixTranspose(worldMat); // mCBUploadPtr is Write-Combine memory memcpy_s(mCBUploadPtr, 64, &mvpMat, 64); memcpy_s(reinterpret_cast<char*>(mCBUploadPtr) + 64, 64, &worldTransMat, 64); } // Get current RTV descriptor auto descHandleRtvStep = mDev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE descHandleRtv = mDescHeapRtv->GetCPUDescriptorHandleForHeapStart(); descHandleRtv.ptr += ((mFrameCount - 1) % BUFFER_COUNT) * descHandleRtvStep; // Get current swap chain ID3D12Resource* d3dBuffer = mD3DBuffer[(mFrameCount - 1) % BUFFER_COUNT].Get(); // Get DSV auto descHandleDsv = mDescHeapDsv->GetCPUDescriptorHandleForHeapStart(); // Barrier Present -> RenderTarget setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); // Viewport & Scissor D3D12_VIEWPORT viewport = {}; viewport.Width = (float)mBufferWidth; viewport.Height = (float)mBufferHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; mCmdList->RSSetViewports(1, &viewport); D3D12_RECT scissor = {}; scissor.right = (LONG)mBufferWidth; scissor.bottom = (LONG)mBufferHeight; mCmdList->RSSetScissorRects(1, &scissor); // Clear DepthTexture mCmdList->ClearDepthStencilView(descHandleDsv, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); // Clear { float clearColor[4] = { 0.1f, 0.2f, 0.3f, 1.0f }; mCmdList->ClearRenderTargetView(descHandleRtv, clearColor, 0, nullptr); } mCmdList->OMSetRenderTargets(1, &descHandleRtv, true, &descHandleDsv); // Draw mCmdList->SetGraphicsRootSignature(mRootSignature.Get()); ID3D12DescriptorHeap* descHeaps[] = { mDescHeapCbvSrvUav.Get() }; mCmdList->SetDescriptorHeaps(ARRAYSIZE(descHeaps), descHeaps); { mCmdList->SetGraphicsRootDescriptorTable(0, mDescHeapCbvSrvUav->GetGPUDescriptorHandleForHeapStart()); mCmdList->SetPipelineState(mPso.Get()); mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); mCmdList->IASetVertexBuffers(0, 1, &mVBView); mCmdList->IASetIndexBuffer(&mIBView); mCmdList->DrawIndexedInstanced(mIndexCount, 1, 0, 0, 0); } // Barrier RenderTarget -> Present setResourceBarrier(mCmdList.Get(), d3dBuffer, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); // Exec CHK(mCmdList->Close()); ID3D12CommandList* const cmdList = mCmdList.Get(); mCmdQueue->ExecuteCommandLists(1, &cmdList); // Present CHK(mSwapChain->Present(1, 0)); // Set queue flushed event CHK(mFence->SetEventOnCompletion(mFrameCount, mFenceEveneHandle)); // Wait for queue flushed // This code would occur CPU stall! CHK(mCmdQueue->Signal(mFence.Get(), mFrameCount)); DWORD wait = WaitForSingleObject(mFenceEveneHandle, 10000); if (wait != WAIT_OBJECT_0) throw runtime_error("Failed WaitForSingleObject()."); CHK(mCmdAlloc->Reset()); CHK(mCmdList->Reset(mCmdAlloc.Get(), nullptr)); }