void ProgramSettings::readLocalStrainCalculatorSettings(const libconfig::Setting& stg) { m_engineSettings.localStrainCalculatorSettings->hstep = stg["hstep"]; m_engineSettings.localStrainCalculatorSettings->xrange = readRange(stg["xrange"]); m_engineSettings.localStrainCalculatorSettings->yrange = readRange(stg["yrange"]); m_engineSettings.localStrainCalculatorSettings->zrange = readRange(stg["zrange"]); }
void ProgramSettings::readCoplanarCorrelationCalculatorSettings(const libconfig::Setting& stg) { m_engineSettings.coplanarCorrelationCalculatorSettings->Q = readMillerReciprocalHexIndices(stg["Q"]); m_engineSettings.coplanarCorrelationCalculatorSettings->nbsteps = stg["nbsteps"]; m_engineSettings.coplanarCorrelationCalculatorSettings->xrange = readRange(stg["xrange"]); m_engineSettings.coplanarCorrelationCalculatorSettings->z1range = readRange(stg["z1range"]); m_engineSettings.coplanarCorrelationCalculatorSettings->z2range = readRange(stg["z2range"]); }
void ProgramSettings::readCoplanarIntensityCalculatorSettings(const libconfig::Setting& stg) { m_engineSettings.coplanarIntensityCalculatorSettings->Q = readMillerReciprocalHexIndices(stg["Q"]); m_engineSettings.coplanarIntensityCalculatorSettings->nbsteps = stg["nbsteps"]; m_engineSettings.coplanarIntensityCalculatorSettings->sigma_x = stg["sigma_x"]; m_engineSettings.coplanarIntensityCalculatorSettings->sigma_z = stg["sigma_z"]; m_engineSettings.coplanarIntensityCalculatorSettings->precision = stg["precision"]; m_engineSettings.coplanarIntensityCalculatorSettings->qxrange = readRange(stg["qxrange"]); m_engineSettings.coplanarIntensityCalculatorSettings->qzrange = readRange(stg["qzrange"]); }
void ProgramSettings::readLocalDisplacementCalculatorSettings(const libconfig::Setting& stg) { if (stg.exists("input")) { m_engineSettings.localDisplacementCalculatorSettings->infile = stg["input"].c_str(); }else { m_engineSettings.localDisplacementCalculatorSettings->infile = ""; m_engineSettings.localDisplacementCalculatorSettings->xrange = readRange(stg["xrange"]); m_engineSettings.localDisplacementCalculatorSettings->yrange = readRange(stg["yrange"]); m_engineSettings.localDisplacementCalculatorSettings->zrange = readRange(stg["zrange"]); } }
FrameResource::FrameResource(ID3D12Device* pDevice, UINT cityRowCount, UINT cityColumnCount) : m_fenceValue(0), m_cityRowCount(cityRowCount), m_cityColumnCount(cityColumnCount) { m_modelMatrices.resize(m_cityRowCount * m_cityColumnCount); // The command allocator is used by the main sample class when // resetting the command list in the main update loop. Each frame // resource needs a command allocator because command allocators // cannot be reused until the GPU is done executing the commands // associated with it. ThrowIfFailed(pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator))); ThrowIfFailed(pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&m_bundleAllocator))); // Create an upload heap for the constant buffers. ThrowIfFailed(pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SceneConstantBuffer) * m_cityRowCount * m_cityColumnCount), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_cbvUploadHeap))); // Map the constant buffers. Note that unlike D3D11, the resource // does not need to be unmapped for use by the GPU. In this sample, // the resource stays 'permenantly' mapped to avoid overhead with // mapping/unmapping each frame. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_cbvUploadHeap->Map(0, &readRange, reinterpret_cast<void**>(&m_pConstantBuffers))); // Update all of the model matrices once; our cities don't move so // we don't need to do this ever again. SetCityPositions(8.0f, -8.0f); }
void RezkonvImporter::loadIngredient( const QString &string, Recipe &recipe, bool &is_sub ) { Ingredient new_ingredient; new_ingredient.amount = 0; //amount not required, so give default of 0 QRegExp cont_test( "^-{1,2}" ); if ( string.trimmed().contains( cont_test ) ) { QString name = string.trimmed(); name.remove( cont_test ); kDebug() << "Appending to last ingredient: " << name ; if ( !recipe.ingList.isEmpty() ) //so it doesn't crash when the first ingredient appears to be a continuation of another recipe.ingList.last().name += ' ' + name; return ; } //amount if ( !string.mid( 0, 7 ).trimmed().isEmpty() ) readRange( string.mid( 0, 7 ), new_ingredient.amount, new_ingredient.amount_offset ); //unit QString unit_str = string.mid( 8, 9 ).trimmed(); new_ingredient.units = Unit( unit_str, new_ingredient.amount ); //name and preparation method new_ingredient.name = string.mid( 18, string.length() - 18 ).trimmed(); //separate out the preparation method QString name_and_prep = new_ingredient.name; int separator_index = name_and_prep.indexOf( "," ); if ( separator_index != -1 ) { new_ingredient.name = name_and_prep.mid( 0, separator_index ).trimmed(); new_ingredient.prepMethodList = ElementList::split(",",name_and_prep.mid( separator_index + 1, name_and_prep.length() ).trimmed() ); } //header (if present) new_ingredient.group = current_header; bool last_is_sub = is_sub; if ( !new_ingredient.prepMethodList.isEmpty() && new_ingredient.prepMethodList.last().name == "or" ) { new_ingredient.prepMethodList.pop_back(); is_sub = true; } else is_sub = false; if ( last_is_sub ) recipe.ingList.last().substitutes.append(new_ingredient); else recipe.ingList.append( new_ingredient ); }
void StringReader :: readRangeList(dynaList< Range > &list, const char *source, const char *idString) { int li, hi; const char *str1, *helpSource = source; // Range* range; // find first valid occurrence of idString int len = strlen(idString); do { if ( ( str1 = strstr(helpSource, idString) ) == NULL ) { return; } helpSource = str1 + 1; } while ( !( isspace( * ( helpSource + len - 1 ) ) ) ); helpSource = str1 + len; // find first non whitespace character // skip whitespaces while ( isspace(* helpSource) ) { helpSource++; } // test if list left bracketed found if ( * helpSource != '{' ) { OOFEM_WARNING("StringReader::readRangeList: parse error - missing left '{'"); list.clear(); return; } helpSource++; // read ranges while ( readRange(& helpSource, li, hi) ) { Range range(li, hi); list.pushBack(range); } // skip whitespaces after last range while ( isspace(* helpSource) ) { helpSource++; } // test for enclosing bracket if ( * helpSource != '}' ) { OOFEM_WARNING("StringReader::readRangeList: parse error - missing end '}'"); list.clear(); return; } }
void DynamicConstantBuffer::Init(ID3D12Device* pDevice) { const UINT bufferSize = m_perFrameConstantBufferSize * m_frameCount; ThrowIfFailed(pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(bufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer) )); CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pMappedConstantBuffer))); }
//コンスタンスバッファ作成 void CBufferDraw::Impl::CreateConstantBuffer() { auto Dev = App::GetApp()->GetDeviceResources(); ThrowIfFailed(Dev->GetDevice()->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SpriteConstantBuffer)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_ConstantBufferUploadHeap)), L"コンスタントバッファ用のアップロードヒープ作成に失敗しました", L"Dev->GetDevice()->CreateCommittedResource()", L"TriangleSprite::CreateConstantBuffer()" ); //コンスタントバッファのビューを作成 //TODO : デスクリプタとビューの違いについて D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_ConstantBufferUploadHeap->GetGPUVirtualAddress(); //コンスタントバッファは256バイトにアラインメント cbvDesc.SizeInBytes = (sizeof(SpriteConstantBuffer) + 255) & ~255; //コンスタントバッファビューを作成すべきデスクプリタヒープ上のハンドルを取得 //シェーダリソースがある場合コンスタントバッファはシェーダリソースビューのあとに設置する CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle( m_CbvSrvUavDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), 0, 0 ); Dev->GetDevice()->CreateConstantBufferView(&cbvDesc, cbvSrvHandle); //コンスタントバッファのアップロードヒープのマップ CD3DX12_RANGE readRange(0, 0); ThrowIfFailed(m_ConstantBufferUploadHeap->Map(0, &readRange, reinterpret_cast<void**>(&m_pConstantBuffer)), L"コンスタントバッファのマップに失敗しました", L"pImpl->m_ConstantBufferUploadHeap->Map()", L"TriangleSprite::CreateConstantBuffer()" ); }
void RezkonvImporter::readRecipe( const QStringList &raw_recipe ) { kapp->processEvents(); //don't want the user to think its frozen... especially for files with thousands of recipes Recipe recipe; QStringList::const_iterator text_it = raw_recipe.begin(); m_end_it = raw_recipe.end(); //title (Titel) text_it++; recipe.title = ( *text_it ).mid( ( *text_it ).indexOf( ":" ) + 1, ( *text_it ).length() ).trimmed(); kDebug() << "Found title: " << recipe.title ; //categories (Kategorien): text_it++; QStringList categories; if ( ( *text_it ).mid( ( *text_it ).indexOf( ":" ) + 1, ( *text_it ).length() ).isEmpty() ) categories = QStringList(); else categories = ( *text_it ).mid( ( *text_it ).indexOf( ":" ) + 1, ( *text_it ).length() ).split( ',', QString::SkipEmptyParts ); for ( QStringList::const_iterator it = categories.constBegin(); it != categories.constEnd(); ++it ) { Element new_cat; new_cat.name = QString( *it ).trimmed(); kDebug() << "Found category: " << new_cat.name ; recipe.categoryList.append( new_cat ); } //yield (Menge) text_it++; //get the number between the ":" and the next space after it QString yield_str = ( *text_it ).trimmed(); yield_str.remove( QRegExp( "^Menge:\\s*" ) ); int sep_index = yield_str.indexOf( ' ' ); if ( sep_index != -1 ) recipe.yield.setType(yield_str.mid( sep_index+1 )); double amount = 0.0, amountOffset = 0.0; readRange( yield_str.mid( 0, sep_index ), amount, amountOffset ); recipe.yield.setAmount(amount); recipe.yield.setAmountOffset(amountOffset); kDebug() << "Found yield: " << recipe.yield.amount(); bool is_sub = false; bool last_line_empty = false; text_it++; while ( text_it != raw_recipe.end() ) { if ( ( *text_it ).isEmpty() ) { last_line_empty = true; text_it++; continue; } if ( ( *text_it ).contains( QRegExp( "^=====.*=$" ) ) ) //is a header { if ( ( *text_it ).contains( "quelle", Qt::CaseInsensitive ) ) { loadReferences( text_it, recipe ); break; //reference lines are the last before the instructions } else loadIngredientHeader( *text_it, recipe ); } //if it has no more than two spaces followed by a non-digit //then we'll assume it is a direction line else if ( last_line_empty && ( *text_it ).contains( QRegExp( "^\\s{0,2}[^\\d\\s=]" ) ) ) break; else loadIngredient( *text_it, recipe, is_sub ); last_line_empty = false; text_it++; } loadInstructions( text_it, recipe ); add ( recipe ); current_header.clear(); }
void D3D12Fullscreen::LoadSizeDependentResources() { m_viewport.Width = static_cast<float>(m_width); m_viewport.Height = static_cast<float>(m_height); m_viewport.MaxDepth = 1.0f; m_scissorRect.right = static_cast<LONG>(m_width); m_scissorRect.bottom = static_cast<LONG>(m_height); // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart()); // Create a RTV for each frame. for (UINT n = 0; n < FrameCount; n++) { ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n]))); m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle); rtvHandle.Offset(1, m_rtvDescriptorSize); WCHAR name[25]; if (swprintf_s(name, L"m_renderTargets[%u]", n) > 0) { SetName(m_renderTargets[n].Get(), name); } } } // Create/update the vertex buffer. When updating the vertex buffer it is important // to ensure that the GPU is finished using the resource before it is released. // The OnSizeChanged method waits for the GPU to be idle before this method is // called. { // Define the geometry for a triangle that stays the same size regardless // of the window size. This is not the recommended way to transform vertices. // The same effect could be achieved by using constant buffers and // transforming a static set of vertices in the vertex shader, but this // sample merely demonstrates modifying a resource that is tied to the render // target size. // Other apps might also resize intermediate render targets or depth stencils // at this time. float x = TriangleWidth / m_viewport.Width; float y = TriangleWidth / m_viewport.Height; Vertex triangleVertices[] = { { { 0.0f, y, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, { { x, -y, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, { { -x, -y, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBufferUpload))); NAME_D3D12_OBJECT(m_vertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBufferUpload->Unmap(0, nullptr); m_commandList->CopyBufferRegion(m_vertexBuffer.Get(), 0, m_vertexBufferUpload.Get(), 0, vertexBufferSize); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } m_resizeResources = false; }
void Plink::displayGeneReport() { // Simply read in any generic results file and list of SNPs by // ranges (which may be subsetted). // if ( false ) // readMapFile(par::mapfile,include,include_pos,nl_actual); ofstream GREP; GREP.open( (par::output_file_name + ".range.report").c_str() , ios::out); map<string, set<Range> > ranges; // Read list of ranges ranges = readRange( par::greport_gene_list ); // Filter ranges if ( par::greport_subset ) ranges = filterRanges( ranges, par::greport_subset_file ); // Open a single results file ifstream RESIN; RESIN.open( par::greport_results.c_str() , ios::in ); // Read first (header) row char cline[par::MAX_LINE_LENGTH]; RESIN.getline(cline,par::MAX_LINE_LENGTH,'\n'); string sline = cline; if (sline=="") error("Problem reading [ " + par::greport_results + " ]\n"); string buf; stringstream ss(sline); vector<string> tokens; while (ss >> buf) tokens.push_back(buf); int chr_column = -1; int bp_column = -1; int pval_column = -1; int snp_column = -1; for (int i=0; i<tokens.size(); i++) { if ( tokens[i] == "CHR" ) chr_column = i; if ( tokens[i] == "BP" ) bp_column = i; if ( tokens[i] == "SNP" ) snp_column = i; if ( tokens[i] == "P" ) pval_column = i; } // Do we have a list of SNPs to specifically extract? set<string> extractSNP; if ( par::extract_set ) { if ( snp_column == -1 ) error("Did not find a SNP field, so cannot use --extract"); checkFileExists( par::extract_file ); PP->printLOG("Only extracting SNPs listed in [ " + par::extract_file + " ]\n"); ifstream IN(par::extract_file.c_str(), ios::in); while ( ! IN.eof() ) { string snpname; IN >> snpname; if ( snpname=="" ) continue; extractSNP.insert(snpname); } IN.close(); PP->printLOG("Read " + int2str( extractSNP.size() ) + " SNPs to extract\n"); } if ( chr_column < 0 || bp_column < 0 ) error("Could not find CHR and BP fields in results file"); map<Range*,vector<string> > annotatedResults; string headerline = sline; int cnt = 0; while ( ! RESIN.eof() ) { // if ( ! par::silent ) // cout << "Processing results line " << ++cnt << " \r"; // vector<string> tokens = tokenizeLine( RESIN ); char cline[par::MAX_LINE_LENGTH]; RESIN.getline(cline,par::MAX_LINE_LENGTH,'\n'); string sline = cline; if (sline=="") continue; string buf; stringstream ss(sline); vector<string> tokens; while (ss >> buf) tokens.push_back(buf); if ( tokens.size() <= chr_column || tokens.size() <= bp_column ) continue; // Using a p-value-filtering field? double pvalue = 0; if ( pval_column != -1 ) { if ( tokens.size() <= pval_column ) continue; if ( ! from_string<double>( pvalue, tokens[pval_column] , std::dec)) continue; if ( par::pfilter && pvalue > par::pfvalue ) continue; } if ( par::extract_set ) { if ( tokens.size() <= snp_column ) continue; if ( extractSNP.find( tokens[snp_column] ) == extractSNP.end() ) continue; } int thisChr = -1; int thisBP = -1; if ( ! from_string<int>( thisChr, tokens[chr_column] , std::dec)) continue; if ( ! from_string<int>( thisBP, tokens[bp_column] , std::dec)) continue; // Do we need to store this? i.e. what ranges is it actually in? // This information is in snp2range Range r1(thisChr,thisBP,thisBP,"dummy"); set<Range*> implicated = rangeIntersect(r1,ranges); set<Range*>::iterator ri = implicated.begin(); while ( ri != implicated.end() ) { string distance = dbl2str(( thisBP - ((*ri)->start + par::make_set_border)) /1000.00 , 4 ) + "kb" ; if ( annotatedResults.find( *ri ) == annotatedResults.end() ) { vector<string> t(2); t[0] = distance; t[1] = sline; annotatedResults.insert(make_pair( (Range *)(*ri) , t ) ); } else { vector<string> & v = annotatedResults.find( *ri )->second; v.push_back(distance); v.push_back(sline); } ++ri; } // Read next line of results } // Iterate through these -- they will be in genomic order, hopefully map<string, set<Range> >::iterator ri = ranges.begin(); while ( ri != ranges.end() ) { set<Range>::iterator si = ri->second.begin(); while ( si != ri->second.end() ) { bool displayed = false; map<Range*,vector<string> >::iterator ari; ari = annotatedResults.find( (Range *)&(*si) ); if ( ari != annotatedResults.end() ) { for (int l=0; l< ari->second.size(); l+=2) { if ( ! displayed ) { GREP << ri->first << " -- chr" << chromosomeName( si->chr ) << ":" << si->start << ".." << si->stop << " ( " << (si->stop - si->start ) / 1000.00 << "kb ) "; if ( par::make_set_border > 0 ) GREP << " including " << par::make_set_border/1000.00 << "kb border "; GREP << "\n\n" << setw(12) << "DIST" << " " << headerline << "\n"; displayed = true; } GREP << setw(12) << ari->second[l] << " " << ari->second[l+1] << "\n"; } } if ( ! displayed ) { if ( par::greport_display_empty ) { GREP << ri->first << " -- chr" << chromosomeName( si->chr ) << ":" << si->start << ".." << si->stop << " ( " << (si->stop - si->start ) / 1000.00 << "kb ) "; if ( par::make_set_border > 0 ) GREP << " including " << par::make_set_border/1000.00 << "kb border "; GREP << " { nothing to report }\n\n"; } } else GREP << "\n\n"; ++si; } ++ri; } RESIN.close(); GREP.close(); if ( ! par::silent ) cout << "\n"; printLOG("Writing per-range report to [ " + par::output_file_name + ".range.report ]\n"); shutdown(); }
HRESULT DX12Framework::AllocateVersionedBuffer(Buffer** ppBuffer) { // // Grab a buffer from our lookaside list if possible. // if (!IsListEmpty(&m_DynamicBufferListHead)) { LIST_ENTRY* pEntry = RemoveHeadList(&m_DynamicBufferListHead); *ppBuffer = static_cast<Buffer*>(pEntry); return S_OK; } // // No available buffers, let's try to allocate a new one. // HRESULT hr; ID3D12Resource* pD3DBuffer = nullptr; CD3DX12_RANGE readRange(0, 0); void* pBaseAddress = nullptr; hr = m_pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(DYNAMIC_BUFFER_SIZE), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&pD3DBuffer)); if (FAILED(hr)) { LOG_WARNING("Failed to create D3D12 buffer resource, hr=0x%.8x", hr); goto cleanup; } // // Obtain a permanent CPU visible address for this buffer. In D3D12, it is okay to // keep a permanent virtual address mapped to an allocation while the resource is // accessed by the GPU. In this case, the semantics of the mapping operation are // always equivalent to the D3D11 MAP_WRITE_NO_OVERWRITE value. // hr = pD3DBuffer->Map(0, &readRange, &pBaseAddress); if (FAILED(hr)) { LOG_WARNING("Failed to map base address for buffer, hr=0x%.8x", hr); goto cleanup; } Buffer* pBuffer = nullptr; try { pBuffer = new Buffer(); } catch (std::bad_alloc&) { LOG_WARNING("Failed to allocate dynamic buffer"); hr = E_OUTOFMEMORY; goto cleanup; } pBuffer->pBaseAddress = (ULONG_PTR)pBaseAddress; pBuffer->pBuffer = pD3DBuffer; *ppBuffer = pBuffer; return S_OK; cleanup: if (pBaseAddress) { pD3DBuffer->Unmap(0, nullptr); } SafeRelease(pD3DBuffer); return hr; }
void ProgramSettings::readMeanStrainCalculatorSettings(const libconfig::Setting& stg) { m_engineSettings.meanStrainCalculatorSettings->hstep = stg["hstep"]; m_engineSettings.meanStrainCalculatorSettings->nbsteps = stg["nbsteps"]; m_engineSettings.meanStrainCalculatorSettings->zrange = readRange(stg["zrange"]); }
/** *************************************************************************************************** * DX12ImageRenderer::CaptureImage * * @brief * Convert a DX12 resource to a CPU-visible linear buffer of pixels. The data is filled * in a user-provided CpuImage struct. * * IMPORTANT: Memory inside pImgOut is allocated on behalf of the caller, so it is their * responsibility to free it. * * @return * S_OK if successful. *************************************************************************************************** */ HRESULT DX12ImageRenderer::CaptureImage( ID3D12Resource* pRes, D3D12_RESOURCE_STATES prevState, UINT newWidth, UINT newHeight, CpuImage* pImgOut, bool bFlipX, bool bFlipY) { HRESULT result = E_FAIL; if ((pRes != nullptr) && (pImgOut != nullptr) && (newWidth > 0) && (newHeight > 0)) { // Create temp assets result = CreateCaptureAssets(pRes, newWidth, newHeight); if (result == S_OK) { result = m_pCmdAllocator->Reset(); } if (result == S_OK) { result = m_pCmdList->Reset(m_pCmdAllocator, m_pPipelineStateGraphics); } // Render work if (result == S_OK) { // Set root sig m_pCmdList->SetGraphicsRootSignature(m_pRootSignatureGraphics); // Set descriptors and tables ID3D12DescriptorHeap* ppHeaps[] = { m_pSrvUavCbHeap }; m_pCmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); CD3DX12_GPU_DESCRIPTOR_HANDLE srvHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterSRV, m_srvUavCbDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE uavHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterUAV, m_srvUavCbDescriptorSize); CD3DX12_GPU_DESCRIPTOR_HANDLE cbHandle(m_pSrvUavCbHeap->GetGPUDescriptorHandleForHeapStart(), RootParameterCBV, m_srvUavCbDescriptorSize); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterSRV, srvHandle); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterUAV, uavHandle); m_pCmdList->SetGraphicsRootDescriptorTable(RootParameterCBV, cbHandle); // Set viewport D3D12_VIEWPORT viewport = {}; viewport.Width = static_cast<float>(newWidth); viewport.Height = static_cast<float>(newHeight); viewport.MaxDepth = 1.0f; m_pCmdList->RSSetViewports(1, &viewport); // Set scissor D3D12_RECT scissorRect = {}; scissorRect.right = static_cast<LONG>(newWidth); scissorRect.bottom = static_cast<LONG>(newHeight); m_pCmdList->RSSetScissorRects(1, &scissorRect); // Update const buf m_constantBufferData.rtWidth = newWidth; m_constantBufferData.flipX = bFlipX ? 1 : 0; m_constantBufferData.flipY = bFlipY ? 1 : 0; CD3DX12_RANGE readRange(0, 0); result = m_pConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin)); memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData)); m_pConstantBuffer->Unmap(0, nullptr); // Set RT CD3DX12_CPU_DESCRIPTOR_HANDLE internalRtvHandle(m_pInternalRtvHeap->GetCPUDescriptorHandleForHeapStart()); m_config.pDevice->CreateRenderTargetView(m_pInternalRT, nullptr, internalRtvHandle); m_pCmdList->OMSetRenderTargets(1, &internalRtvHandle, FALSE, nullptr); // Record commands m_pCmdList->ClearRenderTargetView(internalRtvHandle, ClearColor, 0, nullptr); m_pCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); CD3DX12_RESOURCE_BARRIER barrier = {}; // Render full screen quad and write out UAV barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, prevState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->DrawInstanced(3, 1, 0, 0); #if OVERWRITE_SRC_RES barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST); m_pCmdList->ResourceBarrier(1, &barrier); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pInternalRT, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->CopyResource(pRes, m_pInternalRT); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pInternalRT, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); m_pCmdList->ResourceBarrier(1, &barrier); barrier = CD3DX12_RESOURCE_BARRIER::Transition(pRes, D3D12_RESOURCE_STATE_COPY_DEST, prevState); m_pCmdList->ResourceBarrier(1, &barrier); #endif // Copy UAV to CPU-visible buffer barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pPSWriteBuf, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); m_pCmdList->ResourceBarrier(1, &barrier); m_pCmdList->CopyResource(m_pPSWriteBufReadBack, m_pPSWriteBuf); barrier = CD3DX12_RESOURCE_BARRIER::Transition(m_pPSWriteBuf, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); m_pCmdList->ResourceBarrier(1, &barrier); // Execute the command list result = m_pCmdList->Close(); ID3D12CommandList* ppCommandLists[] = { m_pCmdList }; m_config.pCmdQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); WaitCmdListFinish(); // Read back UAV results void* pUavData = nullptr; result = m_pPSWriteBufReadBack->Map(0, &readRange, &pUavData); if (result == S_OK) { const UINT totalBytes = newWidth * newHeight * BytesPerPixel; pImgOut->pitch = newWidth * BytesPerPixel; pImgOut->width = newWidth; pImgOut->height = newHeight; pImgOut->pData = new char[totalBytes]; memcpy(pImgOut->pData, pUavData, totalBytes); m_pPSWriteBufReadBack->Unmap(0, nullptr); } } // Free temp assets FreeCaptureAssets(); } return result; }
bool D3DClass::Initialize(int screenHeight, int screenWidth, HWND hwnd, bool vsync, bool fullscreen) { D3D_FEATURE_LEVEL featureLevel; HRESULT result; D3D12_COMMAND_QUEUE_DESC commandQueueDesc; IDXGIFactory4* factory; IDXGIAdapter* adapter; IDXGIOutput* adapterOutput; unsigned int numModes, i, numerator, denominator, renderTargetViewDescriptorSize; unsigned long long stringLength; DXGI_MODE_DESC* displayModeList; DXGI_ADAPTER_DESC adapterDesc; DXGI_SWAP_CHAIN_DESC swapChainDesc; IDXGISwapChain* swapChain; D3D12_DESCRIPTOR_HEAP_DESC renderTargetViewHeapDesc; D3D12_CPU_DESCRIPTOR_HANDLE renderTargetViewHandle; // Store the vsync setting. m_vsync_enabled = vsync; // Set the feature level to DirectX 12.1 to enable using all the DirectX 12 features. // Note: Not all cards support full DirectX 12, this feature level may need to be reduced on some cards to 12.0. featureLevel = D3D_FEATURE_LEVEL_11_0; // Create the Direct3D 12 device. result = D3D12CreateDevice(NULL, featureLevel, __uuidof(ID3D12Device), (void**)&m_device); if (FAILED(result)) { MessageBox(hwnd, L"Could not create a DirectX 12.1 device. The default video card does not support DirectX 12.1.", L"DirectX Device Failure", MB_OK); return false; } // Initialize the description of the command queue. ZeroMemory(&commandQueueDesc, sizeof(commandQueueDesc)); // Set up the description of the command queue. commandQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; commandQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; commandQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; commandQueueDesc.NodeMask = 0; // Create the command queue. m_device->CreateCommandQueue(&commandQueueDesc, __uuidof(ID3D12CommandQueue), (void**)&m_commandQueue); // Create a DirectX graphics interface factory. CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&factory); // Use the factory to create an adapter for the primary graphics interface (video card). factory->EnumAdapters(0, &adapter); // Enumerate the primary adapter output (monitor). adapter->EnumOutputs(0, &adapterOutput); // Get the number of modes that fit the DXGI_FORMAT_R8G8B8A8_UNORM display format for the adapter output (monitor). adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL); // Create a list to hold all the possible display modes for this monitor/video card combination. displayModeList = new DXGI_MODE_DESC[numModes]; // Now fill the display mode list structures. adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList); // Now go through all the display modes and find the one that matches the screen height and width. // When a match is found store the numerator and denominator of the refresh rate for that monitor. for (i = 0; i<numModes; i++) { if (displayModeList[i].Height == (unsigned int)screenHeight) { if (displayModeList[i].Width == (unsigned int)screenWidth) { numerator = displayModeList[i].RefreshRate.Numerator; denominator = displayModeList[i].RefreshRate.Denominator; } } } // Get the adapter (video card) description. adapter->GetDesc(&adapterDesc); // Store the dedicated video card memory in megabytes. m_videoCardMemory = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024); // Convert the name of the video card to a character array and store it. wcstombs_s(&stringLength, m_videoCardDescription, 128, adapterDesc.Description, 128); // Release the display mode list. delete[] displayModeList; displayModeList = nullptr; // Release the adapter output. adapterOutput->Release(); adapterOutput = nullptr; // Release the adapter. adapter->Release(); adapter = nullptr; // Initialize the swap chain description. ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); // Set the swap chain to use double buffering. swapChainDesc.BufferCount = 2; // Set the height and width of the back buffers in the swap chain. swapChainDesc.BufferDesc.Height = screenHeight; swapChainDesc.BufferDesc.Width = screenWidth; // Set a regular 32-bit surface for the back buffers. swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // Set the usage of the back buffers to be render target outputs. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Set the swap effect to discard the previous buffer contents after swapping. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // Set the handle for the window to render to. swapChainDesc.OutputWindow = hwnd; // Set to full screen or windowed mode. swapChainDesc.Windowed = !fullscreen; // Set the refresh rate of the back buffer. if (m_vsync_enabled) { swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator; swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator; } else { swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; } // Turn multisampling off. swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; // Set the scan line ordering and scaling to unspecified. swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; // Don't set the advanced flags. swapChainDesc.Flags = 0; // Finally create the swap chain using the swap chain description. factory->CreateSwapChain(m_commandQueue, &swapChainDesc, &swapChain); // Next upgrade the IDXGISwapChain to a IDXGISwapChain3 interface and store it in a private member variable named m_swapChain. // This will allow us to use the newer functionality such as getting the current back buffer index. swapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_swapChain); // Clear pointer to original swap chain interface since we are using version 3 instead (m_swapChain). swapChain = nullptr; // Release the factory now that the swap chain has been created. factory->Release(); factory = nullptr; // Initialize the render target view heap description for the two back buffers. ZeroMemory(&renderTargetViewHeapDesc, sizeof(renderTargetViewHeapDesc)); // Set the number of descriptors to two for our two back buffers. Also set the heap tyupe to render target views. renderTargetViewHeapDesc.NumDescriptors = 2; renderTargetViewHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; renderTargetViewHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; // Create the render target view heap for the back buffers. m_device->CreateDescriptorHeap(&renderTargetViewHeapDesc, __uuidof(ID3D12DescriptorHeap), (void**)&m_renderTargetViewHeap); // Get a handle to the starting memory location in the render target view heap to identify where the render target views will be located for the two back buffers. renderTargetViewHandle = m_renderTargetViewHeap->GetCPUDescriptorHandleForHeapStart(); // Get the size of the memory location for the render target view descriptors. renderTargetViewDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); // Get a pointer to the first back buffer from the swap chain. m_swapChain->GetBuffer(0, __uuidof(ID3D12Resource), (void**)&m_backBufferRenderTarget[0]); // Create a render target view for the first back buffer. m_device->CreateRenderTargetView(m_backBufferRenderTarget[0], NULL, renderTargetViewHandle); // Increment the view handle to the next descriptor location in the render target view heap. renderTargetViewHandle.ptr += renderTargetViewDescriptorSize; // Get a pointer to the second back buffer from the swap chain. m_swapChain->GetBuffer(1, __uuidof(ID3D12Resource), (void**)&m_backBufferRenderTarget[1]); // Create a render target view for the second back buffer. m_device->CreateRenderTargetView(m_backBufferRenderTarget[1], NULL, renderTargetViewHandle); // Finally get the initial index to which buffer is the current back buffer. m_bufferIndex = m_swapChain->GetCurrentBackBufferIndex(); // Create a command allocator. m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&m_commandAllocator); // Create a fence for GPU synchronization. m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence), (void**)&m_fence); // Create an event object for the fence. m_fenceEvent = CreateEvent(nullptr, false, false, nullptr); // Initialize the starting fence value. m_fenceValue = 1; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ID3DBlob* signature; ID3DBlob* error; D3D12SerializeRootSignature( &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)); //Create pipeline state, load and compiler shaders. //Note here to change D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION for debug UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; D3DReadFileToBlob(L"DefaultVS.cso", &m_vertexShader); D3DReadFileToBlob(L"DefaultHS.cso", &m_hullShader); D3DReadFileToBlob(L"DefaultDS.cso", &m_domainShader); D3DReadFileToBlob(L"DefaultPS.cso", &m_pixelShader); std::array<D3D12_INPUT_ELEMENT_DESC, 2> inputElementDescs = { D3D12_INPUT_ELEMENT_DESC{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, D3D12_INPUT_ELEMENT_DESC{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_GRAPHICS_PIPELINE_STATE_DESC pipelineDesc = {}; pipelineDesc.InputLayout = { inputElementDescs.data() , (UINT)inputElementDescs.size() }; pipelineDesc.pRootSignature = m_rootSignature; pipelineDesc.VS = { m_vertexShader->GetBufferPointer(), m_vertexShader->GetBufferSize() }; pipelineDesc.PS = { m_pixelShader->GetBufferPointer(), m_pixelShader->GetBufferSize() }; pipelineDesc.HS = { m_hullShader->GetBufferPointer(), m_hullShader->GetBufferSize() }; pipelineDesc.DS = { m_domainShader->GetBufferPointer(), m_domainShader->GetBufferSize() }; pipelineDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT_WIREFRAME); pipelineDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); pipelineDesc.DepthStencilState.DepthEnable = false; pipelineDesc.DepthStencilState.StencilEnable = false; pipelineDesc.SampleMask = UINT_MAX; pipelineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; pipelineDesc.NumRenderTargets = 1; pipelineDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; pipelineDesc.SampleDesc.Count = 1; m_device->CreateGraphicsPipelineState(&pipelineDesc, IID_PPV_ARGS(&m_pipelineState)); // Create a basic command list. m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, m_pipelineState, IID_PPV_ARGS(&m_commandList)); // Initially we need to close the command list during initialization as it is created in a recording state. m_commandList->Close(); Vertex triangleVertices[] = { { { 0.0f, 0.5f, 0.f }, { 1.f, 0.f, 0.f, 1.f } }, { { 0.5f, -0.5f, 0.f },{ 0.f, 1.f, 0.f, 1.f } }, { { -0.5f, -0.5f, 0.f },{ 0.f, 0.f, 1.f, 1.f } }, }; const UINT vertexBufferSize = sizeof(triangleVertices); m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBuffer)); UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)); memcpy(pVertexDataBegin, triangleVertices, vertexBufferSize); m_vertexBuffer->Unmap(0, nullptr); m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; m_viewport.Height = screenHeight; m_viewport.Width = screenWidth; m_viewport.MaxDepth = 1000.f; m_viewport.MinDepth = 0.1f; m_viewport.TopLeftX = 0.f; m_viewport.TopLeftY = 0.f; m_scissorRect.left = 0; m_scissorRect.right = screenWidth; m_scissorRect.top = 0; m_scissorRect.bottom = screenHeight; unsigned long long fenceToWaitFor = m_fenceValue; m_commandQueue->Signal(m_fence, fenceToWaitFor); m_fenceValue++; // Wait until the GPU is done rendering. if (m_fence->GetCompletedValue() < fenceToWaitFor) { m_fence->SetEventOnCompletion(fenceToWaitFor, m_fenceEvent); WaitForSingleObject(m_fenceEvent, INFINITE); } return true; }
// Load the sample assets. void D3D12HeterogeneousMultiadapter::LoadAssets() { // Create the root signatures. { CD3DX12_ROOT_PARAMETER rootParameters[2]; rootParameters[0].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_VERTEX); rootParameters[1].InitAsConstantBufferView(1, 0, D3D12_SHADER_VISIBILITY_PIXEL); CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_devices[Primary]->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); CD3DX12_DESCRIPTOR_RANGE ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); CD3DX12_ROOT_PARAMETER blurRootParameters[3]; blurRootParameters[0].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_PIXEL); blurRootParameters[1].InitAsDescriptorTable(_countof(ranges), ranges, D3D12_SHADER_VISIBILITY_PIXEL); blurRootParameters[2].InitAsConstantBufferView(1, 0, D3D12_SHADER_VISIBILITY_PIXEL); CD3DX12_STATIC_SAMPLER_DESC staticPointSampler(0); staticPointSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; staticPointSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; CD3DX12_STATIC_SAMPLER_DESC staticLinearSampler(1); staticLinearSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; staticLinearSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; D3D12_STATIC_SAMPLER_DESC staticSamplers[] = { staticPointSampler, staticLinearSampler }; rootSignatureDesc.Init(_countof(blurRootParameters), blurRootParameters, _countof(staticSamplers), staticSamplers, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_devices[Secondary]->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_blurRootSignature))); } // Create the pipeline states, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> vertexShaderBlur; ComPtr<ID3DBlob> pixelShaderBlurU; ComPtr<ID3DBlob> pixelShaderBlurV; ComPtr<ID3DBlob> error; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VShader", "vs_5_0", compileFlags, 0, &vertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PShader", "ps_5_0", compileFlags, 0, &pixelShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"blurShaders.hlsl").c_str(), nullptr, nullptr, "VSSimpleBlur", "vs_5_0", compileFlags, 0, &vertexShaderBlur, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"blurShaders.hlsl").c_str(), nullptr, nullptr, "PSSimpleBlurU", "ps_5_0", compileFlags, 0, &pixelShaderBlurU, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"blurShaders.hlsl").c_str(), nullptr, nullptr, "PSSimpleBlurV", "ps_5_0", compileFlags, 0, &pixelShaderBlurV, &error)); // Define the vertex input layouts. const D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; const D3D12_INPUT_ELEMENT_DESC blurInputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the graphics pipeline state objects (PSOs). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT); psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_devices[Primary]->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); psoDesc.InputLayout = { blurInputElementDescs, _countof(blurInputElementDescs) }; psoDesc.pRootSignature = m_blurRootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShaderBlur.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShaderBlurU.Get()); psoDesc.DepthStencilState.DepthEnable = false; psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; ThrowIfFailed(m_devices[Secondary]->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_blurPipelineStates[0]))); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShaderBlurV.Get()); ThrowIfFailed(m_devices[Secondary]->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_blurPipelineStates[1]))); } // Create the command lists. ThrowIfFailed(m_devices[Primary]->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_directCommandAllocators[Primary][m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_directCommandLists[Primary]))); ThrowIfFailed(m_devices[Primary]->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COPY, m_copyCommandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_copyCommandList))); ThrowIfFailed(m_copyCommandList->Close()); ThrowIfFailed(m_devices[Secondary]->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_directCommandAllocators[Secondary][m_frameIndex].Get(), m_blurPipelineStates[0].Get(), IID_PPV_ARGS(&m_directCommandLists[Secondary]))); // Note: ComPtr's are CPU objects but these resources need to stay in scope until // the command list that references them has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resources are not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; ComPtr<ID3D12Resource> fullscreenQuadVertexBufferUpload; // Create the vertex buffer for the primary adapter. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, TriangleHalfWidth, TriangleDepth } }, { { TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } }, { { -TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } } }; const UINT vertexBufferSize = sizeof(triangleVertices); ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUpload))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast<UINT8*>(triangleVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_directCommandLists[Primary].Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData); m_directCommandLists[Primary]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = sizeof(triangleVertices); } // Create the vertex buffer for the secondary adapter. { // Define the geometry for a fullscreen triangle. VertexPositionUV quadVertices[] = { { { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } }, // Bottom left. { { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, // Top left. { { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, // Bottom right. { { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } }, // Top right. }; const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_devices[Secondary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_fullscreenQuadVertexBuffer))); ThrowIfFailed(m_devices[Secondary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fullscreenQuadVertexBufferUpload))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast<UINT8*>(quadVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_directCommandLists[Secondary].Get(), m_fullscreenQuadVertexBuffer.Get(), fullscreenQuadVertexBufferUpload.Get(), 0, 0, 1, &vertexData); m_directCommandLists[Secondary]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_fullscreenQuadVertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_fullscreenQuadVertexBufferView.BufferLocation = m_fullscreenQuadVertexBuffer->GetGPUVirtualAddress(); m_fullscreenQuadVertexBufferView.StrideInBytes = sizeof(VertexPositionUV); m_fullscreenQuadVertexBufferView.SizeInBytes = sizeof(quadVertices); } // Create the depth stencil view. { D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; const CD3DX12_CLEAR_VALUE clearValue(DXGI_FORMAT_D32_FLOAT, 1.0f, 0); ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(&m_depthStencil) )); m_devices[Primary]->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); } // Create the constant buffers. { { const UINT64 constantBufferSize = sizeof(ConstantBufferData) * MaxTriangleCount * FrameCount; ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); // Setup constant buffer data. for (UINT n = 0; n < MaxTriangleCount; n++) { m_constantBufferData[n].velocity = XMFLOAT4(GetRandomFloat(0.01f, 0.02f), 0.0f, 0.0f, 0.0f); m_constantBufferData[n].offset = XMFLOAT4(GetRandomFloat(-5.0f, -1.5f), GetRandomFloat(-1.0f, 1.0f), GetRandomFloat(0.0f, 2.0f), 0.0f); m_constantBufferData[n].color = XMFLOAT4(GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), 1.0f); XMStoreFloat4x4(&m_constantBufferData[n].projection, XMMatrixTranspose(XMMatrixPerspectiveFovLH(XM_PIDIV4, m_aspectRatio, 0.01f, 20.0f))); } // Map the constant buffer. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData[0], constantBufferSize / FrameCount); } { const UINT64 workloadConstantBufferSize = sizeof(WorkloadConstantBufferData) * FrameCount; ThrowIfFailed(m_devices[Primary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(workloadConstantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_workloadConstantBuffer))); // Setup constant buffer data. m_workloadConstantBufferData.loopCount = m_psLoopCount; // Map the constant buffer. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_workloadConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pWorkloadCbvDataBegin))); memcpy(m_pWorkloadCbvDataBegin, &m_workloadConstantBufferData, workloadConstantBufferSize / FrameCount); } { const UINT64 blurWorkloadConstantBufferSize = sizeof(WorkloadConstantBufferData) * FrameCount; ThrowIfFailed(m_devices[Secondary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(blurWorkloadConstantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_blurWorkloadConstantBuffer))); // Setup constant buffer data. m_blurWorkloadConstantBufferData.loopCount = m_blurPSLoopCount; // Map the constant buffer. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_blurWorkloadConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pBlurWorkloadCbvDataBegin))); memcpy(m_pBlurWorkloadCbvDataBegin, &m_blurWorkloadConstantBufferData, blurWorkloadConstantBufferSize / FrameCount); } { ThrowIfFailed(m_devices[Secondary]->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(BlurConstantBufferData)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_blurConstantBuffer))); // Map the constant buffer. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_blurConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pBlurCbvDataBegin))); // Setup constant buffer data. m_pBlurCbvDataBegin[0].offset = 0.5f; m_pBlurCbvDataBegin[0].textureDimensions.x = static_cast<float>(m_width); m_pBlurCbvDataBegin[0].textureDimensions.y = static_cast<float>(m_height); // Unmap the constant buffer because we don't update this again. // If we ever do, it should be buffered by the number of frames like other constant buffers. const CD3DX12_RANGE emptyRange(0, 0); m_blurConstantBuffer->Unmap(0, &emptyRange); m_pBlurCbvDataBegin = nullptr; } } // Close the command lists and execute them to begin the vertex buffer copies into the default heaps. for (UINT i = 0; i < GraphicsAdaptersCount; i++) { ThrowIfFailed(m_directCommandLists[i]->Close()); ID3D12CommandList* ppCommandLists[] = { m_directCommandLists[i].Get() }; m_directCommandQueues[i]->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); } // Create synchronization objects and wait until assets have been uploaded to the GPU. // We use a cross-adapter fence for handling Signals and Waits between adapters. // We use regular fences for things that don't need to be cross adapter because they don't need the additional overhead associated with being cross-adapter. { // Fence used to control CPU pacing. ThrowIfFailed(m_devices[Secondary]->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_frameFence))); // Fence used by the primary adapter to signal its copy queue that it has completed rendering. // When this is signaled, the primary adapter's copy queue can begin copying to the cross-adapter shared resource. ThrowIfFailed(m_devices[Primary]->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_renderFence))); // Cross-adapter shared fence used by both adapters. // Used by the primary adapter to signal the secondary adapter that it has completed copying to the cross-adapter shared resource. // When this is signaled, the secondary adapter can begin its work. ThrowIfFailed(m_devices[Primary]->CreateFence(0, D3D12_FENCE_FLAG_SHARED | D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER, IID_PPV_ARGS(&m_crossAdapterFences[Primary]))); // For now, require GENERIC_ALL access. HANDLE fenceHandle = nullptr; ThrowIfFailed(m_devices[Primary]->CreateSharedHandle( m_crossAdapterFences[Primary].Get(), nullptr, GENERIC_ALL, nullptr, &fenceHandle)); HRESULT openSharedHandleResult = m_devices[Secondary]->OpenSharedHandle(fenceHandle, IID_PPV_ARGS(&m_crossAdapterFences[Secondary])); // We can close the handle after opening the cross-adapter shared fence. CloseHandle(fenceHandle); ThrowIfFailed(openSharedHandleResult); for (UINT i = 0; i < GraphicsAdaptersCount; i++) { // Create an event handle to use for frame synchronization. m_fenceEvents[i] = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); if (m_fenceEvents == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(static_cast<GraphicsAdapter>(i)); } } }
// Load the sample assets. void D3D12Fullscreen::LoadAssets() { // Create a root signature consisting of a descriptor table with a single CBV. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; CD3DX12_ROOT_PARAMETER rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> error; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, &error)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); NAME_D3D12_OBJECT(m_pipelineState); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); LoadSizeDependentResources(); // Create/update the vertex buffer. { // Define the geometry for a thin quad that will animate across the screen. const float x = QuadWidth / 2.0f; const float y = QuadHeight / 2.0f; Vertex quadVertices[] = { { { -x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { -x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBufferUpload))); NAME_D3D12_OBJECT(m_vertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, quadVertices, sizeof(quadVertices)); m_vertexBufferUpload->Unmap(0, nullptr); m_commandList->CopyBufferRegion(m_vertexBuffer.Get(), 0, m_vertexBufferUpload.Get(), 0, vertexBufferSize); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create the constant buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SceneConstantBuffer) * FrameCount), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); NAME_D3D12_OBJECT(m_constantBuffer); // Describe and create constant buffer views. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = sizeof(SceneConstantBuffer); CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); for (UINT n = 0; n < FrameCount; n++) { m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cbvDesc.BufferLocation += sizeof(SceneConstantBuffer); cpuHandle.Offset(m_cbvDescriptorSize); } // Initialize and map the constant buffers. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. ZeroMemory(&m_constantBufferData, sizeof(m_constantBufferData)); CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData)); } // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } }
FrameResource::FrameResource(ID3D12Device* pDevice, ID3D12PipelineState* pPso, ID3D12PipelineState* pShadowMapPso, ID3D12DescriptorHeap* pDsvHeap, ID3D12DescriptorHeap* pCbvSrvHeap, D3D12_VIEWPORT* pViewport, UINT frameResourceIndex) : m_fenceValue(0), m_pipelineState(pPso), m_pipelineStateShadowMap(pShadowMapPso) { for (int i = 0; i < CommandListCount; i++) { ThrowIfFailed(pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[i]))); ThrowIfFailed(pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[i].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandLists[i]))); // Close these command lists; don't record into them for now. ThrowIfFailed(m_commandLists[i]->Close()); } for (int i = 0; i < NumContexts; i++) { // Create command list allocators for worker threads. One alloc is // for the shadow pass command list, and one is for the scene pass. ThrowIfFailed(pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_shadowCommandAllocators[i]))); ThrowIfFailed(pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_sceneCommandAllocators[i]))); ThrowIfFailed(pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_shadowCommandAllocators[i].Get(), m_pipelineStateShadowMap.Get(), IID_PPV_ARGS(&m_shadowCommandLists[i]))); ThrowIfFailed(pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_sceneCommandAllocators[i].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_sceneCommandLists[i]))); // Close these command lists; don't record into them for now. We will // reset them to a recording state when we start the render loop. ThrowIfFailed(m_shadowCommandLists[i]->Close()); ThrowIfFailed(m_sceneCommandLists[i]->Close()); } // Describe and create the shadow map texture. CD3DX12_RESOURCE_DESC shadowTexDesc( D3D12_RESOURCE_DIMENSION_TEXTURE2D, 0, static_cast<UINT>(pViewport->Width), static_cast<UINT>(pViewport->Height), 1, 1, DXGI_FORMAT_R32_TYPELESS, 1, 0, D3D12_TEXTURE_LAYOUT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); D3D12_CLEAR_VALUE clearValue; // Performance tip: Tell the runtime at resource creation the desired clear value. clearValue.Format = DXGI_FORMAT_D32_FLOAT; clearValue.DepthStencil.Depth = 1.0f; clearValue.DepthStencil.Stencil = 0; ThrowIfFailed(pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &shadowTexDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(&m_shadowTexture))); // Get a handle to the start of the descriptor heap then offset // it based on the frame resource index. const UINT dsvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); CD3DX12_CPU_DESCRIPTOR_HANDLE depthHandle(pDsvHeap->GetCPUDescriptorHandleForHeapStart(), 1 + frameResourceIndex, dsvDescriptorSize); // + 1 for the shadow map. // Describe and create the shadow depth view and cache the CPU // descriptor handle. D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {}; depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilViewDesc.Texture2D.MipSlice = 0; pDevice->CreateDepthStencilView(m_shadowTexture.Get(), &depthStencilViewDesc, depthHandle); m_shadowDepthView = depthHandle; // Get a handle to the start of the descriptor heap then offset it // based on the existing textures and the frame resource index. Each // frame has 1 SRV (shadow tex) and 2 CBVs. const UINT nullSrvCount = 2; // Null descriptors at the start of the heap. const UINT textureCount = _countof(SampleAssets::Textures); // Diffuse + normal textures near the start of the heap. Ideally, track descriptor heap contents/offsets at a higher level. const UINT cbvSrvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvCpuHandle(pCbvSrvHeap->GetCPUDescriptorHandleForHeapStart()); CD3DX12_GPU_DESCRIPTOR_HANDLE cbvSrvGpuHandle(pCbvSrvHeap->GetGPUDescriptorHandleForHeapStart()); m_nullSrvHandle = cbvSrvGpuHandle; cbvSrvCpuHandle.Offset(nullSrvCount + textureCount + (frameResourceIndex * FrameCount), cbvSrvDescriptorSize); cbvSrvGpuHandle.Offset(nullSrvCount + textureCount + (frameResourceIndex * FrameCount), cbvSrvDescriptorSize); // Describe and create a shader resource view (SRV) for the shadow depth // texture and cache the GPU descriptor handle. This SRV is for sampling // the shadow map from our shader. It uses the same texture that we use // as a depth-stencil during the shadow pass. D3D12_SHADER_RESOURCE_VIEW_DESC shadowSrvDesc = {}; shadowSrvDesc.Format = DXGI_FORMAT_R32_FLOAT; shadowSrvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shadowSrvDesc.Texture2D.MipLevels = 1; shadowSrvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; pDevice->CreateShaderResourceView(m_shadowTexture.Get(), &shadowSrvDesc, cbvSrvCpuHandle); m_shadowDepthHandle = cbvSrvGpuHandle; // Increment the descriptor handles. cbvSrvCpuHandle.Offset(cbvSrvDescriptorSize); cbvSrvGpuHandle.Offset(cbvSrvDescriptorSize); // Create the constant buffers. const UINT constantBufferSize = (sizeof(ConstantBuffer) + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1); // must be a multiple 256 bytes ThrowIfFailed(pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_shadowConstantBuffer))); ThrowIfFailed(pDevice->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_sceneConstantBuffer))); // Map the constant buffers and cache their heap pointers. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_shadowConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&mp_shadowConstantBufferWO))); ThrowIfFailed(m_sceneConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&mp_sceneConstantBufferWO))); // Create the constant buffer views: one for the shadow pass and // another for the scene pass. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.SizeInBytes = constantBufferSize; // Describe and create the shadow constant buffer view (CBV) and // cache the GPU descriptor handle. cbvDesc.BufferLocation = m_shadowConstantBuffer->GetGPUVirtualAddress(); pDevice->CreateConstantBufferView(&cbvDesc, cbvSrvCpuHandle); m_shadowCbvHandle = cbvSrvGpuHandle; // Increment the descriptor handles. cbvSrvCpuHandle.Offset(cbvSrvDescriptorSize); cbvSrvGpuHandle.Offset(cbvSrvDescriptorSize); // Describe and create the scene constant buffer view (CBV) and // cache the GPU descriptor handle. cbvDesc.BufferLocation = m_sceneConstantBuffer->GetGPUVirtualAddress(); pDevice->CreateConstantBufferView(&cbvDesc, cbvSrvCpuHandle); m_sceneCbvHandle = cbvSrvGpuHandle; // Batch up command lists for execution later. const UINT batchSize = _countof(m_sceneCommandLists) + _countof(m_shadowCommandLists) + 3; m_batchSubmit[0] = m_commandLists[CommandListPre].Get(); memcpy(m_batchSubmit + 1, m_shadowCommandLists, _countof(m_shadowCommandLists) * sizeof(ID3D12CommandList*)); m_batchSubmit[_countof(m_shadowCommandLists) + 1] = m_commandLists[CommandListMid].Get(); memcpy(m_batchSubmit + _countof(m_shadowCommandLists) + 2, m_sceneCommandLists, _countof(m_sceneCommandLists) * sizeof(ID3D12CommandList*)); m_batchSubmit[batchSize - 1] = m_commandLists[CommandListPost].Get(); }
// Load the sample assets. void D3D12ExecuteIndirect::LoadAssets() { // Create the root signatures. { CD3DX12_ROOT_PARAMETER rootParameters[GraphicsRootParametersCount]; rootParameters[Cbv].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_VERTEX); CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); // Create compute signature. CD3DX12_DESCRIPTOR_RANGE ranges[2]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0); ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0); CD3DX12_ROOT_PARAMETER computeRootParameters[ComputeRootParametersCount]; computeRootParameters[SrvUavTable].InitAsDescriptorTable(2, ranges); computeRootParameters[RootConstants].InitAsConstants(4, 0); CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc; computeRootSignatureDesc.Init(_countof(computeRootParameters), computeRootParameters); ThrowIfFailed(D3D12SerializeRootSignature(&computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_computeRootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> computeShader; ComPtr<ID3DBlob> error; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"compute.hlsl").c_str(), nullptr, nullptr, "CSMain", "cs_5_0", compileFlags, 0, &computeShader, &error)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() }; psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() }; psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT); psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); // Describe and create the compute pipeline state object (PSO). D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; computePsoDesc.pRootSignature = m_computeRootSignature.Get(); computePsoDesc.CS = { reinterpret_cast<UINT8*>(computeShader->GetBufferPointer()), computeShader->GetBufferSize() }; ThrowIfFailed(m_device->CreateComputePipelineState(&computePsoDesc, IID_PPV_ARGS(&m_computeState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeCommandAllocators[m_frameIndex].Get(), m_computeState.Get(), IID_PPV_ARGS(&m_computeCommandList))); ThrowIfFailed(m_computeCommandList->Close()); // Note: ComPtr's are CPU objects but these resources need to stay in scope until // the command list that references them has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resources are not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; ComPtr<ID3D12Resource> commandBufferUpload; // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, TriangleHalfWidth, TriangleDepth } }, { { TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } }, { { -TriangleHalfWidth, -TriangleHalfWidth, TriangleDepth } } }; const UINT vertexBufferSize = sizeof(triangleVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUpload))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast<UINT8*>(triangleVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = sizeof(triangleVertices); } // Create the depth stencil view. { D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; D3D12_CLEAR_VALUE depthOptimizedClearValue = {}; depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT; depthOptimizedClearValue.DepthStencil.Depth = 1.0f; depthOptimizedClearValue.DepthStencil.Stencil = 0; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthOptimizedClearValue, IID_PPV_ARGS(&m_depthStencil) )); m_device->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); } // Create the constant buffers. { const UINT constantBufferDataSize = TriangleResourceCount * sizeof(ConstantBufferData); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(constantBufferDataSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.SizeInBytes = sizeof(ConstantBufferData); // Create constant buffer views to access the upload buffer. for (UINT n = 0; n < TriangleCount; n++) { m_constantBufferData[n].velocity = XMFLOAT4(GetRandomFloat(0.01f, 0.02f), 0.0f, 0.0f, 0.0f); m_constantBufferData[n].offset = XMFLOAT4(GetRandomFloat(-5.0f, -1.5f), GetRandomFloat(-1.0f, 1.0f), GetRandomFloat(0.0f, 2.0f), 0.0f); m_constantBufferData[n].color = XMFLOAT4(GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), GetRandomFloat(0.5f, 1.0f), 1.0f); XMStoreFloat4x4(&m_constantBufferData[n].projection, XMMatrixTranspose(XMMatrixPerspectiveFovLH(XM_PIDIV4, m_aspectRatio, 0.01f, 20.0f))); } // Map the constant buffers. We don't unmap this until the app closes. // Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData[0], TriangleCount * sizeof(ConstantBufferData)); // Create shader resource views (SRV) of the constant buffers for the // compute shader to read from. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Buffer.NumElements = TriangleCount; srvDesc.Buffer.StructureByteStride = sizeof(ConstantBufferData); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE cbvSrvHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), CbvSrvOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { srvDesc.Buffer.FirstElement = frame * TriangleCount; m_device->CreateShaderResourceView(m_constantBuffer.Get(), &srvDesc, cbvSrvHandle); cbvSrvHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } } // Create the command signature used for indirect drawing. { // Each command consists of a CBV update and a DrawInstanced call. D3D12_INDIRECT_ARGUMENT_DESC argumentDescs[2] = {}; argumentDescs[0].Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW; argumentDescs[0].ConstantBufferView.RootParameterIndex = Cbv; argumentDescs[1].Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc = {}; commandSignatureDesc.pArgumentDescs = argumentDescs; commandSignatureDesc.NumArgumentDescs = _countof(argumentDescs); commandSignatureDesc.ByteStride = sizeof(IndirectCommand); ThrowIfFailed(m_device->CreateCommandSignature(&commandSignatureDesc, m_rootSignature.Get(), IID_PPV_ARGS(&m_commandSignature))); } // Create the command buffers and UAVs to store the results of the compute work. { std::vector<IndirectCommand> commands; commands.resize(TriangleResourceCount); const UINT commandBufferSize = CommandBufferSizePerFrame * FrameCount; D3D12_RESOURCE_DESC commandBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(commandBufferSize); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &commandBufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_commandBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(commandBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&commandBufferUpload))); D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = m_constantBuffer->GetGPUVirtualAddress(); UINT commandIndex = 0; for (UINT frame = 0; frame < FrameCount; frame++) { for (UINT n = 0; n < TriangleCount; n++) { commands[commandIndex].cbv = gpuAddress; commands[commandIndex].drawArguments.VertexCountPerInstance = 3; commands[commandIndex].drawArguments.InstanceCount = 1; commands[commandIndex].drawArguments.StartVertexLocation = 0; commands[commandIndex].drawArguments.StartInstanceLocation = 0; commandIndex++; gpuAddress += sizeof(ConstantBufferData); } } // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the command buffer. D3D12_SUBRESOURCE_DATA commandData = {}; commandData.pData = reinterpret_cast<UINT8*>(&commands[0]); commandData.RowPitch = commandBufferSize; commandData.SlicePitch = commandData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_commandBuffer.Get(), commandBufferUpload.Get(), 0, 0, 1, &commandData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_commandBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)); // Create SRVs for the command buffers. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Buffer.NumElements = TriangleCount; srvDesc.Buffer.StructureByteStride = sizeof(IndirectCommand); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE commandsHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), CommandsOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { srvDesc.Buffer.FirstElement = frame * TriangleCount; m_device->CreateShaderResourceView(m_commandBuffer.Get(), &srvDesc, commandsHandle); commandsHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } // Create the unordered access views (UAVs) that store the results of the compute work. CD3DX12_CPU_DESCRIPTOR_HANDLE processedCommandsHandle(m_cbvSrvUavHeap->GetCPUDescriptorHandleForHeapStart(), ProcessedCommandsOffset, m_cbvSrvUavDescriptorSize); for (UINT frame = 0; frame < FrameCount; frame++) { // Allocate a buffer large enough to hold all of the indirect commands // for a single frame as well as a UAV counter. commandBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(CommandBufferSizePerFrame + sizeof(UINT), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &commandBufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_processedCommandBuffers[frame]))); D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = TriangleCount; uavDesc.Buffer.StructureByteStride = sizeof(IndirectCommand); uavDesc.Buffer.CounterOffsetInBytes = CommandBufferSizePerFrame; uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; m_device->CreateUnorderedAccessView( m_processedCommandBuffers[frame].Get(), m_processedCommandBuffers[frame].Get(), &uavDesc, processedCommandsHandle); processedCommandsHandle.Offset(CbvSrvUavDescriptorCountPerFrame, m_cbvSrvUavDescriptorSize); } // Allocate a buffer that can be used to reset the UAV counters and initialize // it to 0. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(UINT)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_processedCommandBufferCounterReset))); UINT8* pMappedCounterReset = nullptr; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_processedCommandBufferCounterReset->Map(0, &readRange, reinterpret_cast<void**>(&pMappedCounterReset))); ZeroMemory(pMappedCounterReset, sizeof(UINT)); m_processedCommandBufferCounterReset->Unmap(0, nullptr); } // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_computeFence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } }
// Load the sample assets. void D3D12HelloTexture::LoadAssets() { // Create the root signature. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); CD3DX12_ROOT_PARAMETER rootParameters[1]; rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 0.5f, 0.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f } }, { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBuffer->Unmap(0, nullptr); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> textureUploadHeap; // Create the texture. { // Describe and create a Texture2D. D3D12_RESOURCE_DESC textureDesc = {}; textureDesc.MipLevels = 1; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.Width = TextureWidth; textureDesc.Height = TextureHeight; textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; textureDesc.DepthOrArraySize = 1; textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Quality = 0; textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_texture))); const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1); // Create the GPU upload buffer. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&textureUploadHeap))); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. std::vector<UINT8> texture = GenerateTextureData(); D3D12_SUBRESOURCE_DATA textureData = {}; textureData.pData = &texture[0]; textureData.RowPitch = TextureWidth * TexturePixelSize; textureData.SlicePitch = textureData.RowPitch * TextureHeight; UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); // Describe and create a SRV for the texture. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = textureDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart()); } // Close the command list and execute it to begin the initial GPU setup. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForPreviousFrame(); } }
void D3D12PipelineStateCache::LoadAssets() { // Create the root signature. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[RootParametersCount]; ranges[RootParameterSRV].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); CD3DX12_ROOT_PARAMETER1 rootParameters[RootParametersCount]; rootParameters[RootParameterUberShaderCB].InitAsConstantBufferView(0, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL); rootParameters[RootParameterCB].InitAsConstantBufferView(1, 0, D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC, D3D12_SHADER_VISIBILITY_ALL); rootParameters[RootParameterSRV].InitAsDescriptorTable(1, &ranges[RootParameterSRV]); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = 9999.0f; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), nullptr, IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexIndexBufferUpload; // Vertex and Index Buffer. { const VertexPositionColor cubeVertices[] = { { { -1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Top Left { { 1.0f, 1.0f, -1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Back Top Right { { 1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Front Top Right { { -1.0f, 1.0f, 1.0f, 1.0f }, { GetRandomColor(), GetRandomColor(), GetRandomColor() } }, // Front Top Left { { -1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Bottom Left { { 1.0f, -1.0f, -1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Back Bottom Right { { 1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Front Bottom Right { { -1.0f, -1.0f, 1.0f, 1.0f }, { GetRandomColor(),GetRandomColor(), GetRandomColor() } }, // Front Bottom Left }; const UINT cubeIndices[] = { 0, 1, 3, 1, 2, 3, 3, 2, 7, 6, 7, 2, 2, 1, 6, 5, 6, 1, 1, 0, 5, 4, 5, 0, 0, 3, 4, 7, 4, 3, 7, 6, 4, 5, 4, 6, }; static const VertexPositionUV quadVertices[] = { { { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, // Bottom Left { { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } }, // Top Left { { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } }, // Bottom Right { { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, // Top Right }; const UINT vertexIndexBufferSize = sizeof(cubeIndices) + sizeof(cubeVertices) + sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexIndexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexIndexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexIndexBufferUpload))); NAME_D3D12_OBJECT(m_vertexIndexBuffer); UINT8* mappedUploadHeap = nullptr; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(vertexIndexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&mappedUploadHeap))); // Fill in part of the upload heap with our index and vertex data. UINT8* heapLocation = static_cast<UINT8*>(mappedUploadHeap); memcpy(heapLocation, cubeVertices, sizeof(cubeVertices)); heapLocation += sizeof(cubeVertices); memcpy(heapLocation, cubeIndices, sizeof(cubeIndices)); heapLocation += sizeof(cubeIndices); memcpy(heapLocation, quadVertices, sizeof(quadVertices)); // Pack the vertices and indices into their destination by copying from the upload heap. m_commandList->CopyBufferRegion(m_vertexIndexBuffer.Get(), 0, vertexIndexBufferUpload.Get(), 0, vertexIndexBufferSize); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexIndexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER | D3D12_RESOURCE_STATE_INDEX_BUFFER)); // Create the index and vertex buffer views. m_cubeVbv.BufferLocation = m_vertexIndexBuffer.Get()->GetGPUVirtualAddress(); m_cubeVbv.SizeInBytes = sizeof(cubeVertices); m_cubeVbv.StrideInBytes = sizeof(VertexPositionColor); m_cubeIbv.BufferLocation = m_cubeVbv.BufferLocation + sizeof(cubeVertices); m_cubeIbv.SizeInBytes = sizeof(cubeIndices); m_cubeIbv.Format = DXGI_FORMAT_R32_UINT; m_quadVbv.BufferLocation = m_cubeIbv.BufferLocation + sizeof(cubeIndices); m_quadVbv.SizeInBytes = sizeof(quadVertices); m_quadVbv.StrideInBytes = sizeof(VertexPositionUV); } // Create the constant buffer. m_dynamicCB.Init(m_device.Get()); // Close the command list and execute it to begin the vertex/index buffer copy // into the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } m_psoLibrary.Build(m_device.Get(), m_rootSignature.Get()); UpdateWindowTextPso(); }
// Load the assets. HRESULT VolumetricAnimation::LoadAssets() { HRESULT hr; // Create a root signature consisting of a descriptor table with a CBV SRV and a sampler. { CD3DX12_DESCRIPTOR_RANGE ranges[3]; CD3DX12_ROOT_PARAMETER rootParameters[3]; ranges[0].Init( D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0 ); ranges[1].Init( D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0 ); ranges[2].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0 ); rootParameters[RootParameterCBV].InitAsDescriptorTable( 1, &ranges[0], D3D12_SHADER_VISIBILITY_ALL ); rootParameters[RootParameterSRV].InitAsDescriptorTable( 1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL ); rootParameters[RootParameterUAV].InitAsDescriptorTable( 1, &ranges[2], D3D12_SHADER_VISIBILITY_ALL ); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; // Allow input layout and deny unnecessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init( _countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags ); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; V( D3D12SerializeRootSignature( &rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error ) ); if ( error ) PRINTERROR( reinterpret_cast< const char* >( error->GetBufferPointer() ) ); VRET( m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS( &m_graphicsRootSignature ) ) ); DXDebugName( m_graphicsRootSignature ); // Create compute signature. Must change visibility for the SRV. rootParameters[RootParameterSRV].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; CD3DX12_ROOT_SIGNATURE_DESC computeRootSignatureDesc( _countof( rootParameters ), rootParameters, 0, nullptr ); VRET( D3D12SerializeRootSignature( &computeRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error ) ); VRET( m_device->CreateRootSignature( 0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS( &m_computeRootSignature ) ) ); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; ComPtr<ID3DBlob> computeShader; UINT compileFlags = 0; VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "vsmain", "vs_5_0", compileFlags, 0, &vertexShader ) ); VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "psmain", "ps_5_0", compileFlags, 0, &pixelShader ) ); VRET( CompileShaderFromFile( GetAssetFullPath( _T( "VolumetricAnimation_shader.hlsl" ) ).c_str(), nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, "csmain", "cs_5_0", compileFlags, 0, &computeShader ) ); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; CD3DX12_DEPTH_STENCIL_DESC depthStencilDesc( D3D12_DEFAULT ); depthStencilDesc.DepthEnable = true; depthStencilDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; depthStencilDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; depthStencilDesc.StencilEnable = FALSE; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof( inputElementDescs ) }; psoDesc.pRootSignature = m_graphicsRootSignature.Get(); psoDesc.VS = { reinterpret_cast< UINT8* >( vertexShader->GetBufferPointer() ), vertexShader->GetBufferSize() }; psoDesc.PS = { reinterpret_cast< UINT8* >( pixelShader->GetBufferPointer() ), pixelShader->GetBufferSize() }; psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC( D3D12_DEFAULT ); psoDesc.BlendState = CD3DX12_BLEND_DESC( D3D12_DEFAULT ); psoDesc.DepthStencilState = depthStencilDesc; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; VRET( m_device->CreateGraphicsPipelineState( &psoDesc, IID_PPV_ARGS( &m_pipelineState ) ) ); DXDebugName( m_pipelineState ); // Describe and create the compute pipeline state object (PSO). D3D12_COMPUTE_PIPELINE_STATE_DESC computePsoDesc = {}; computePsoDesc.pRootSignature = m_computeRootSignature.Get(); computePsoDesc.CS = { reinterpret_cast< UINT8* >( computeShader->GetBufferPointer() ), computeShader->GetBufferSize() }; VRET( m_device->CreateComputePipelineState( &computePsoDesc, IID_PPV_ARGS( &m_computeState ) ) ); DXDebugName( m_computeState ); } // Create the compute command list. VRET( m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_COMPUTE, m_computeCmdAllocator.Get(),m_computeState.Get(), IID_PPV_ARGS( &m_computeCmdList ) ) ); DXDebugName( m_computeCmdList ); VRET( m_computeCmdList->Close() ); // Create the graphics command list. VRET( m_device->CreateCommandList( 0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_graphicCmdAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS( &m_graphicCmdList ) ) ); DXDebugName( m_graphicCmdList ); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> volumeBufferUploadHeap; // Create the volumeBuffer. { UINT volumeBufferSize = m_volumeDepth*m_volumeHeight*m_volumeWidth * 4 * sizeof( UINT8 ); D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer( volumeBufferSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS ); D3D12_RESOURCE_DESC uploadBufferDesc = CD3DX12_RESOURCE_DESC::Buffer( volumeBufferSize ); VRET( m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ),D3D12_HEAP_FLAG_NONE, &bufferDesc,D3D12_RESOURCE_STATE_COPY_DEST,nullptr,IID_PPV_ARGS( &m_volumeBuffer ) ) ); const UINT64 uploadBufferSize = GetRequiredIntermediateSize( m_volumeBuffer.Get(), 0, 1 ); // Create the GPU upload buffer. VRET( m_device->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ),D3D12_HEAP_FLAG_NONE, &uploadBufferDesc,D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,IID_PPV_ARGS( &volumeBufferUploadHeap ) ) ); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. UINT8* volumeBuffer = ( UINT8* ) malloc( volumeBufferSize ); memset( volumeBuffer, 64, volumeBufferSize ); //float radius = m_volumeHeight / 2.f; float a = m_volumeWidth / 2.f; float b = m_volumeHeight / 2.f; float c = m_volumeDepth / 2.f; float radius = sqrt( a*a + b*b + c*c ); for ( UINT z = 0; z < m_volumeDepth; z++ ) for ( UINT y = 0; y < m_volumeHeight; y++ ) for ( UINT x = 0; x < m_volumeWidth; x++ ) { float _x = x - m_volumeWidth / 2.f; float _y = y - m_volumeHeight / 2.f; float _z = z - m_volumeDepth / 2.f; //float currentRaidus =abs(_x)+abs(_y)+abs(_z); float currentRaidus = sqrt( _x*_x + _y*_y + _z*_z ); float scale = currentRaidus *3.f / radius; UINT idx = 4 - (UINT)floor( scale ); UINT interm = ( UINT ) ( 192 * scale +0.5f ); UINT8 col = interm % 192+1; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 0] += col * m_constantBufferData.colVal[idx].x; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 1] += col * m_constantBufferData.colVal[idx].y; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 2] += col * m_constantBufferData.colVal[idx].z; volumeBuffer[( x + y*m_volumeWidth + z*m_volumeHeight*m_volumeWidth ) * 4 + 3] = m_constantBufferData.colVal[idx].w; } D3D12_SUBRESOURCE_DATA volumeBufferData = {}; volumeBufferData.pData = &volumeBuffer[0]; volumeBufferData.RowPitch = volumeBufferSize; volumeBufferData.SlicePitch = volumeBufferData.RowPitch; UpdateSubresources( m_graphicCmdList.Get(), m_volumeBuffer.Get(), volumeBufferUploadHeap.Get(), 0, 0, 1, &volumeBufferData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_volumeBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS ) ); // Describe and create a SRV for the volumeBuffer. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = m_volumeDepth*m_volumeHeight*m_volumeWidth; srvDesc.Buffer.StructureByteStride = 4 * sizeof( UINT8 ); srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE srvHandle( m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart(), RootParameterSRV, m_cbvsrvuavDescriptorSize ); m_device->CreateShaderResourceView( m_volumeBuffer.Get(), &srvDesc, srvHandle ); // Describe and create a UAV for the volumeBuffer. D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = m_volumeWidth*m_volumeHeight*m_volumeDepth; uavDesc.Buffer.StructureByteStride = 4 * sizeof( UINT8 ); uavDesc.Buffer.CounterOffsetInBytes = 0; uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; CD3DX12_CPU_DESCRIPTOR_HANDLE uavHandle( m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart(), RootParameterUAV, m_cbvsrvuavDescriptorSize ); m_device->CreateUnorderedAccessView( m_volumeBuffer.Get(), nullptr, &uavDesc, uavHandle ); free( volumeBuffer ); } // Create the vertex buffer. // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; { // Define the geometry for a triangle. Vertex cubeVertices[] = { { XMFLOAT3( -128.f, -128.f, -128.f ) }, { XMFLOAT3( -128.f, -128.f, 128.f ) }, { XMFLOAT3( -128.f, 128.f, -128.f ) }, { XMFLOAT3( -128.f, 128.f, 128.f ) }, { XMFLOAT3( 128.f, -128.f, -128.f )}, { XMFLOAT3( 128.f, -128.f, 128.f )}, { XMFLOAT3( 128.f, 128.f, -128.f )}, { XMFLOAT3( 128.f, 128.f, 128.f )}, }; const UINT vertexBufferSize = sizeof( cubeVertices ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &vertexBufferUpload ) ) ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS( &m_vertexBuffer ) ) ); DXDebugName( m_vertexBuffer ); D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast< UINT8* >( cubeVertices ); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexBufferSize; UpdateSubresources<1>( m_graphicCmdList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER )); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof( Vertex ); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create the index buffer // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> indexBufferUpload; { uint16_t cubeIndices[] = { 0,2,1, 1,2,3, 4,5,6, 5,7,6, 0,1,5, 0,5,4, 2,6,7, 2,7,3, 0,4,6, 0,6,2, 1,3,7, 1,7,5, }; const UINT indexBufferSize = sizeof( cubeIndices ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( indexBufferSize ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &indexBufferUpload ) ) ); VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( indexBufferSize ), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS( &m_indexBuffer ) ) ); DXDebugName( m_indexBuffer ); D3D12_SUBRESOURCE_DATA indexData = {}; indexData.pData = reinterpret_cast< UINT8* >( cubeIndices ); indexData.RowPitch = indexBufferSize; indexData.SlicePitch = indexBufferSize; UpdateSubresources<1>( m_graphicCmdList.Get(), m_indexBuffer.Get(), indexBufferUpload.Get(), 0, 0, 1, &indexData ); m_graphicCmdList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_indexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_INDEX_BUFFER ) ); m_indexBufferView.BufferLocation = m_indexBuffer->GetGPUVirtualAddress(); m_indexBufferView.SizeInBytes = sizeof( cubeIndices ); m_indexBufferView.Format = DXGI_FORMAT_R16_UINT; } // Create the constant buffer { VRET( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( 1024 * 64 ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &m_constantBuffer ) ) ); DXDebugName( m_constantBuffer ); // Describe and create a constant buffer view. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = ( sizeof( ConstantBuffer ) + 255 ) & ~255; // CB size is required to be 256-byte aligned. m_device->CreateConstantBufferView( &cbvDesc, m_cbvsrvuavHeap->GetCPUDescriptorHandleForHeapStart() ); // Initialize and map the constant buffers. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange( 0, 0 ); // We do not intend to read from this resource on the CPU. VRET( m_constantBuffer->Map( 0, &readRange, reinterpret_cast< void** >( &m_pCbvDataBegin ) ) ); memcpy( m_pCbvDataBegin, &m_constantBufferData, sizeof( m_constantBufferData ) ); } // Close the command list and execute it to begin the initial GPU setup. VRET( m_graphicCmdList->Close() ); ID3D12CommandList* ppCommandLists[] = { m_graphicCmdList.Get() }; m_graphicCmdQueue->ExecuteCommandLists( _countof( ppCommandLists ), ppCommandLists ); // Create synchronization objects and wait until assets have been uploaded to the GPU. { VRET( m_device->CreateFence( 0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS( &m_fence ) ) ); DXDebugName( m_fence ); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent( nullptr, FALSE, FALSE, nullptr ); if ( m_fenceEvent == nullptr ) { VRET( HRESULT_FROM_WIN32( GetLastError() ) ); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGraphicsCmd(); } XMVECTORF32 vecEye = { 500.0f, 500.0f, -500.0f }; XMVECTORF32 vecAt = { 0.0f, 0.0f, 0.0f }; m_camera.SetViewParams( vecEye, vecAt ); m_camera.SetEnablePositionMovement( true ); m_camera.SetButtonMasks( MOUSE_RIGHT_BUTTON, MOUSE_WHEEL, MOUSE_LEFT_BUTTON ); return S_OK; }
// Load the sample assets. void D3D12PredicationQueries::LoadAssets() { // Create a root signature consisting of a single CBV parameter. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); NAME_D3D12_OBJECT(m_rootSignature); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Enable alpha blending so we can visualize the occlusion query results. CD3DX12_BLEND_DESC blendDesc(D3D12_DEFAULT); blendDesc.RenderTarget[0] = { TRUE, FALSE, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_LOGIC_OP_NOOP, D3D12_COLOR_WRITE_ENABLE_ALL, }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = blendDesc; psoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT); psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); NAME_D3D12_OBJECT(m_pipelineState); // Disable color writes and depth writes for the occlusion query's state. psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0; psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_queryState))); NAME_D3D12_OBJECT(m_queryState); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); NAME_D3D12_OBJECT(m_commandList); // Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ComPtr<ID3D12Resource> vertexBufferUpload; // Create the vertex buffer. { // Create geometry for two quads and a bounding box for the occlusion query. // Geometry will be rendered back-to-front to support transparency in the scene. Vertex quadVertices[] = { // Far quad - in practice this would be a complex geometry. { { -0.25f, -0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { -0.25f, 0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { 0.25f, 0.25f * m_aspectRatio, 0.5f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, // Near quad. { { -0.5f, -0.35f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.65f } }, { { -0.5f, 0.35f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.65f } }, { { 0.5f, -0.35f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f, 0.0f, 0.65f } }, { { 0.5f, 0.35f * m_aspectRatio, 0.0f }, { 1.0f, 1.0f, 0.0f, 0.65f } }, // Far quad bounding box used for occlusion query (offset slightly to avoid z-fighting). { { -0.25f, -0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { -0.25f, 0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, 0.25f * m_aspectRatio, 0.4999f }, { 0.0f, 0.0f, 0.0f, 1.0f } }, }; const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vertexBufferUpload))); NAME_D3D12_OBJECT(m_vertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. D3D12_SUBRESOURCE_DATA vertexData = {}; vertexData.pData = reinterpret_cast<UINT8*>(quadVertices); vertexData.RowPitch = vertexBufferSize; vertexData.SlicePitch = vertexData.RowPitch; UpdateSubresources<1>(m_commandList.Get(), m_vertexBuffer.Get(), vertexBufferUpload.Get(), 0, 0, 1, &vertexData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = sizeof(quadVertices); } // Create the constant buffers. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(FrameCount * sizeof(m_constantBufferData)), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); NAME_D3D12_OBJECT(m_constantBuffer); // Map and initialize the constant buffer. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); ZeroMemory(m_pCbvDataBegin, FrameCount * sizeof(m_constantBufferData)); // Create constant buffer views to access the upload buffer. CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = m_constantBuffer->GetGPUVirtualAddress(); D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.SizeInBytes = sizeof(SceneConstantBuffer); for (UINT n = 0; n < FrameCount; n++) { cbvDesc.BufferLocation = gpuAddress; m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cpuHandle.Offset(m_cbvSrvDescriptorSize); gpuAddress += cbvDesc.SizeInBytes; cbvDesc.BufferLocation = gpuAddress; m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cpuHandle.Offset(m_cbvSrvDescriptorSize); gpuAddress += cbvDesc.SizeInBytes; } } // Create the depth stencil view. { D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {}; depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT; depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE; D3D12_CLEAR_VALUE depthOptimizedClearValue = {}; depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT; depthOptimizedClearValue.DepthStencil.Depth = 1.0f; depthOptimizedClearValue.DepthStencil.Stencil = 0; ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, m_width, m_height, 1, 0, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL), D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthOptimizedClearValue, IID_PPV_ARGS(&m_depthStencil) )); NAME_D3D12_OBJECT(m_depthStencil); m_device->CreateDepthStencilView(m_depthStencil.Get(), &depthStencilDesc, m_dsvHeap->GetCPUDescriptorHandleForHeapStart()); } // Create the query result buffer. { D3D12_RESOURCE_DESC queryResultDesc = CD3DX12_RESOURCE_DESC::Buffer(8); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &queryResultDesc, D3D12_RESOURCE_STATE_PREDICATION, nullptr, IID_PPV_ARGS(&m_queryResult) )); NAME_D3D12_OBJECT(m_queryResult); } // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } }
// Load the sample assets. void D3D12Fullscreen::LoadAssets() { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } // Create a root signature consisting of a descriptor table with a single CBV. { CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_sceneRootSignature))); NAME_D3D12_OBJECT(m_sceneRootSignature); } // Create a root signature consisting of a descriptor table with a SRV and a sampler. { CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; // We don't modify the SRV in the post-processing command list after // SetGraphicsRootDescriptorTable is executed on the GPU so we can use the default // range behavior: D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL); // Allow input layout and pixel shader access and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; // Create a sampler. D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.MipLODBias = 0; sampler.MaxAnisotropy = 0; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; sampler.MinLOD = 0.0f; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderRegister = 0; sampler.RegisterSpace = 0; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_postRootSignature))); NAME_D3D12_OBJECT(m_postRootSignature); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> sceneVertexShader; ComPtr<ID3DBlob> scenePixelShader; ComPtr<ID3DBlob> postVertexShader; ComPtr<ID3DBlob> postPixelShader; ComPtr<ID3DBlob> error; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"sceneShaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &sceneVertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"sceneShaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &scenePixelShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"postShaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &postVertexShader, &error)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"postShaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &postPixelShader, &error)); // Define the vertex input layouts. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; D3D12_INPUT_ELEMENT_DESC scaleInputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state objects (PSOs). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_sceneRootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(sceneVertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(scenePixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_scenePipelineState))); NAME_D3D12_OBJECT(m_scenePipelineState); psoDesc.InputLayout = { scaleInputElementDescs, _countof(scaleInputElementDescs) }; psoDesc.pRootSignature = m_postRootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(postVertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(postPixelShader.Get()); ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_postPipelineState))); NAME_D3D12_OBJECT(m_postPipelineState); } // Single-use command allocator and command list for creating resources. ComPtr<ID3D12CommandAllocator> commandAllocator; ComPtr<ID3D12GraphicsCommandList> commandList; ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator))); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator.Get(), nullptr, IID_PPV_ARGS(&commandList))); // Create the command lists. { ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_sceneCommandAllocators[m_frameIndex].Get(), m_scenePipelineState.Get(), IID_PPV_ARGS(&m_sceneCommandList))); NAME_D3D12_OBJECT(m_sceneCommandList); ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_postCommandAllocators[m_frameIndex].Get(), m_postPipelineState.Get(), IID_PPV_ARGS(&m_postCommandList))); NAME_D3D12_OBJECT(m_postCommandList); // Close the command lists. ThrowIfFailed(m_sceneCommandList->Close()); ThrowIfFailed(m_postCommandList->Close()); } LoadSizeDependentResources(); LoadSceneResolutionDependentResources(); // Create/update the vertex buffer. ComPtr<ID3D12Resource> sceneVertexBufferUpload; { // Define the geometry for a thin quad that will animate across the screen. const float x = QuadWidth / 2.0f; const float y = QuadHeight / 2.0f; SceneVertex quadVertices[] = { { { -x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { -x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, -y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } }, { { x, y, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_sceneVertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&sceneVertexBufferUpload))); NAME_D3D12_OBJECT(m_sceneVertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(sceneVertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, quadVertices, sizeof(quadVertices)); sceneVertexBufferUpload->Unmap(0, nullptr); commandList->CopyBufferRegion(m_sceneVertexBuffer.Get(), 0, sceneVertexBufferUpload.Get(), 0, vertexBufferSize); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_sceneVertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_sceneVertexBufferView.BufferLocation = m_sceneVertexBuffer->GetGPUVirtualAddress(); m_sceneVertexBufferView.StrideInBytes = sizeof(SceneVertex); m_sceneVertexBufferView.SizeInBytes = vertexBufferSize; } // Create/update the fullscreen quad vertex buffer. ComPtr<ID3D12Resource> postVertexBufferUpload; { // Define the geometry for a fullscreen quad. PostVertex quadVertices[] = { { { -1.0f, -1.0f, 0.0f, 1.0f }, { 0.0f, 0.0f } }, // Bottom left. { { -1.0f, 1.0f, 0.0f, 1.0f }, { 0.0f, 1.0f } }, // Top left. { { 1.0f, -1.0f, 0.0f, 1.0f }, { 1.0f, 0.0f } }, // Bottom right. { { 1.0f, 1.0f, 0.0f, 1.0f }, { 1.0f, 1.0f } } // Top right. }; const UINT vertexBufferSize = sizeof(quadVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_postVertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&postVertexBufferUpload))); NAME_D3D12_OBJECT(m_postVertexBuffer); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(postVertexBufferUpload->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, quadVertices, sizeof(quadVertices)); postVertexBufferUpload->Unmap(0, nullptr); commandList->CopyBufferRegion(m_postVertexBuffer.Get(), 0, postVertexBufferUpload.Get(), 0, vertexBufferSize); commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_postVertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); // Initialize the vertex buffer views. m_postVertexBufferView.BufferLocation = m_postVertexBuffer->GetGPUVirtualAddress(); m_postVertexBufferView.StrideInBytes = sizeof(PostVertex); m_postVertexBufferView.SizeInBytes = vertexBufferSize; } // Create the constant buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(sizeof(SceneConstantBuffer) * FrameCount), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_sceneConstantBuffer))); NAME_D3D12_OBJECT(m_sceneConstantBuffer); // Describe and create constant buffer views. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_sceneConstantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = sizeof(SceneConstantBuffer); CD3DX12_CPU_DESCRIPTOR_HANDLE cpuHandle(m_cbvSrvHeap->GetCPUDescriptorHandleForHeapStart(), 1, m_cbvSrvDescriptorSize); for (UINT n = 0; n < FrameCount; n++) { m_device->CreateConstantBufferView(&cbvDesc, cpuHandle); cbvDesc.BufferLocation += sizeof(SceneConstantBuffer); cpuHandle.Offset(m_cbvSrvDescriptorSize); } // Map and initialize the constant buffer. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_sceneConstantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_sceneConstantBufferData, sizeof(m_sceneConstantBufferData)); } // Close the resource creation command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(commandList->Close()); ID3D12CommandList* ppCommandLists[] = { commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute before continuing. WaitForGpu(); } }
// Load the sample assets. void D3D12HelloTriangle::LoadAssets() { // Create an empty root signature. { CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() }; psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() }; psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); // Command lists are created in the recording state, but there is nothing // to record yet. The main loop expects it to be closed, so close it now. ThrowIfFailed(m_commandList->Close()); // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBuffer->Unmap(0, nullptr); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForPreviousFrame(); } }
// Load the sample assets. void D3D12HelloConstBuffers::LoadAssets() { // Create a root signature consisting of a descriptor table with a single CBV. { D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {}; // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1; if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } CD3DX12_DESCRIPTOR_RANGE1 ranges[1]; CD3DX12_ROOT_PARAMETER1 rootParameters[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state, which includes compiling and loading shaders. { ComPtr<ID3DBlob> vertexShader; ComPtr<ID3DBlob> pixelShader; #if defined(_DEBUG) // Enable better shader debugging with the graphics debugging tools. UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #else UINT compileFlags = 0; #endif ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr)); ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr)); // Define the vertex input layout. D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 } }; // Describe and create the graphics pipeline state object (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_commandList))); // Command lists are created in the recording state, but there is nothing // to record yet. The main loop expects it to be closed, so close it now. ThrowIfFailed(m_commandList->Close()); // Create the vertex buffer. { // Define the geometry for a triangle. Vertex triangleVertices[] = { { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } }, { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } }, { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof(triangleVertices); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); // Copy the triangle data to the vertex buffer. UINT8* pVertexDataBegin; CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin))); memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices)); m_vertexBuffer->Unmap(0, nullptr); // Initialize the vertex buffer view. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof(Vertex); m_vertexBufferView.SizeInBytes = vertexBufferSize; } // Create the constant buffer. { ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(1024 * 64), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_constantBuffer))); // Describe and create a constant buffer view. D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress(); cbvDesc.SizeInBytes = (sizeof(SceneConstantBuffer) + 255) & ~255; // CB size is required to be 256-byte aligned. m_device->CreateConstantBufferView(&cbvDesc, m_cbvHeap->GetCPUDescriptorHandleForHeapStart()); // Map and initialize the constant buffer. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU. ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin))); memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData)); } // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValue = 1; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForPreviousFrame(); } }