From 5eb8edf741ffe295805717bc343a139328ecc6d2 Mon Sep 17 00:00:00 2001 From: Neil Forbes-Richardson Date: Tue, 16 Jan 2018 18:52:53 +1100 Subject: [PATCH] Started the compressed vertex stream stuff. HLSL backend generator will write out unused parameters to satisfy compiler in the cases they may be unused, but compiler doesn't like their omission --- apps/testbed/compressed_model.cpp | 170 +++++++++--------- apps/testbed/compressed_model.h | 15 +- apps/testbed/test_entry.cpp | 5 +- res/default_compressed.material | 3 + res/default_compressed.material.metadata | 6 + res/shaders/base_geometry.esh | 10 +- res/shaders/default_compressed.esf | 70 ++++++++ src/graphics/converters/converter_shader.cpp | 24 ++- .../converters/shader_backend_hlsl.cpp | 68 ++++++- src/graphics/converters/shader_backend_hlsl.h | 19 +- src/graphics/private/shader.cpp | 3 + 11 files changed, 284 insertions(+), 109 deletions(-) create mode 100644 res/default_compressed.material create mode 100644 res/default_compressed.material.metadata create mode 100644 res/shaders/default_compressed.esf diff --git a/apps/testbed/compressed_model.cpp b/apps/testbed/compressed_model.cpp index e80a357..1e27bd4 100644 --- a/apps/testbed/compressed_model.cpp +++ b/apps/testbed/compressed_model.cpp @@ -370,7 +370,6 @@ namespace MeshTools { auto AddVertex = [this](Vertex a) -> i32 { i32 idx = vertices_.size(); -#if 1 auto it = std::find_if(vertexHashes_.begin(), vertexHashes_.end(), [&a, this](const u32& b) { if(a.hash_ == b) { @@ -382,7 +381,6 @@ namespace MeshTools if(it != vertexHashes_.end()) return (i32)(it - vertexHashes_.begin()); -#endif vertices_.push_back(a); vertexHashes_.push_back(a.hash_); return idx; @@ -403,6 +401,32 @@ namespace MeshTools vertexHashes_.reserve(mesh->mNumFaces * 3); triangles_.reserve(mesh->mNumFaces); + for(unsigned int i = 0; i < mesh->mNumVertices; ++i) + { + auto GetVertex = [mesh](int idx) { + Vertex v = {}; + v.position_ = &mesh->mVertices[idx].x; + if(mesh->mNormals) + v.normal_ = &mesh->mNormals[idx].x; + if(mesh->mTangents) + v.tangent_ = &mesh->mTangents[idx].x; + if(mesh->mTextureCoords[0]) + v.texcoord_ = &mesh->mTextureCoords[0][idx].x; + if(mesh->mColors[0]) + v.color_ = &mesh->mColors[0][idx].r; + else + v.color_ = Math::Vec4(1.0f, 1.0f, 1.0f, 1.0f); + v.Initialize(); + return v; + }; + + Vertex v = GetVertex(i); + bounds_.ExpandBy(v.position_); + + vertices_.push_back(v); + vertexHashes_.push_back(v.hash_); + } + for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { // Skip anything that isn't a triangle. @@ -412,28 +436,7 @@ namespace MeshTools int ib = mesh->mFaces[i].mIndices[1]; int ic = mesh->mFaces[i].mIndices[2]; - auto GetVertex = [mesh](int idx) { - Vertex v = {}; - v.position_ = &mesh->mVertices[idx].x; - if(mesh->mNormals) - v.normal_ = &mesh->mNormals[idx].x; - if(mesh->mTangents) - v.tangent_ = &mesh->mTangents[idx].x; - if(mesh->mTextureCoords[0]) - v.texcoord_ = &mesh->mTextureCoords[0][idx].x; - if(mesh->mColors[0]) - v.color_ = &mesh->mColors[0][idx].r; - else - v.color_ = Math::Vec4(1.0f, 1.0f, 1.0f, 1.0f); - v.Initialize(); - return v; - }; - - Vertex a = GetVertex(ia); - Vertex b = GetVertex(ib); - Vertex c = GetVertex(ic); - - AddFace(a, b, c); + triangles_.emplace_back(ia, ib, ic); } } } @@ -447,6 +450,11 @@ namespace MeshTools }); } + void ReorderIndices() + { + + } + void ImportMeshCluster(Mesh* mesh, i32 firstTri, i32 numTris) { if(firstTri >= mesh->triangles_.size()) @@ -767,9 +775,7 @@ CompressedModel::CompressedModel(const char* sourceFile) if(scene) { - i32 clusterSize = 1024; Core::Vector meshes; - Core::Vector meshClusters; i32 numVertices = 0; i32 numIndices = 0; @@ -801,7 +807,8 @@ CompressedModel::CompressedModel(const char* sourceFile) material = "default.material"; materials_.emplace_back(std::move(material)); - Core::Log("Mesh %u: Diameter: %.3f\n", i, mesh->bounds_.Diameter()); + material = "default_compressed.material"; + compressedMaterials_.emplace_back(std::move(material)); MeshTools::Texture packedPositionTex; MeshTools::Texture packedNormalTex; @@ -819,32 +826,10 @@ CompressedModel::CompressedModel(const char* sourceFile) } Core::StreamDesc outStream(nullptr, Core::DataType::UNORM, 8, 2); - auto packedNormalTexGPU = packedNormalTex.Create(GPU::Format::R8G8_UNORM, outStream, "PackedNormalTex"); - - - Mesh outMesh; - outMesh.baseCluster_ = clusters_.size(); - outMesh.numClusters_ = (mesh->triangles_.size() + clusterSize - 1) / clusterSize; - meshes_.push_back(outMesh); + normalTex_ = packedNormalTex.Create(GPU::Format::R8G8_UNORM, outStream, "PackedNormalTex"); - for(i32 triIdx = 0; triIdx < mesh->triangles_.size(); triIdx += clusterSize) - { - auto* meshCluster = new MeshTools::Mesh(); - meshCluster->ImportMeshCluster(mesh, triIdx, clusterSize); - meshClusters.push_back(meshCluster); - - MeshCluster outMeshCluster; - outMeshCluster.meshIdx_ = i; - outMeshCluster.baseDrawArg_ = outMesh.baseCluster_; - outMeshCluster.baseVertex_ = numVertices; - outMeshCluster.baseIndex_ = numIndices; - outMeshCluster.numIndices_ = meshCluster->triangles_.size() * 3; - clusters_.push_back(outMeshCluster); - clusterBounds_.push_back(meshCluster->bounds_); - - numVertices += meshCluster->vertices_.size(); - numIndices += meshCluster->triangles_.size() * 3; - } + numIndices += mesh->triangles_.size() * 3; + numVertices += mesh->vertices_.size(); } // Setup vertex declaration. @@ -885,15 +870,19 @@ CompressedModel::CompressedModel(const char* sourceFile) BinaryStream idxStream; i32 indexOffset = 0; - auto cluster = clusters_.begin(); - for(const auto& meshCluster : meshClusters) + i32 vertexOffset = 0; + for(const auto& mesh : meshes) { - indexOffset = cluster->baseVertex_; - ++cluster; + Mesh outMesh; + outMesh.bounds_ = mesh->bounds_; + outMesh.baseIndex_ = indexOffset; + outMesh.baseVertex_ = vertexOffset; + outMesh.numIndices_ = mesh->triangles_.size() * 3; + meshes_.push_back(outMesh); - for(i32 triIdx = 0; triIdx < meshCluster->triangles_.size(); ++triIdx) + for(i32 triIdx = 0; triIdx < mesh->triangles_.size(); ++triIdx) { - auto tri = meshCluster->triangles_[triIdx]; + auto tri = mesh->triangles_[triIdx]; idxStream.Write(tri.idx_[0] + indexOffset); idxStream.Write(tri.idx_[1] + indexOffset); idxStream.Write(tri.idx_[2] + indexOffset); @@ -905,7 +894,7 @@ CompressedModel::CompressedModel(const char* sourceFile) const i32 stride = GPU::GetStride(elements.data(), numElements, vtxStreamIdx); if(stride > 0) { - Core::Vector vertexData(stride * meshCluster->vertices_.size(), 0); + Core::Vector vertexData(stride * mesh->vertices_.size(), 0); Core::Vector inStreamDescs; Core::Vector outStreamDescs; Core::Vector numComponents; @@ -921,19 +910,19 @@ CompressedModel::CompressedModel(const char* sourceFile) switch(element.usage_) { case GPU::VertexUsage::POSITION: - inStreamDesc.data_ = &meshCluster->vertices_.data()->position_; + inStreamDesc.data_ = &mesh->vertices_.data()->position_; break; case GPU::VertexUsage::NORMAL: - inStreamDesc.data_ = &meshCluster->vertices_.data()->normal_; + inStreamDesc.data_ = &mesh->vertices_.data()->normal_; break; case GPU::VertexUsage::TEXCOORD: - inStreamDesc.data_ = &meshCluster->vertices_.data()->texcoord_; + inStreamDesc.data_ = &mesh->vertices_.data()->texcoord_; break; case GPU::VertexUsage::TANGENT: - inStreamDesc.data_ = &meshCluster->vertices_.data()->tangent_; + inStreamDesc.data_ = &mesh->vertices_.data()->tangent_; break; case GPU::VertexUsage::COLOR: - inStreamDesc.data_ = &meshCluster->vertices_.data()->color_; + inStreamDesc.data_ = &mesh->vertices_.data()->color_; break; default: DBG_ASSERT(false); @@ -964,8 +953,8 @@ CompressedModel::CompressedModel(const char* sourceFile) auto inStreamDesc = inStreamDescs[elementStreamIdx]; auto outStreamDesc = outStreamDescs[elementStreamIdx]; - DBG_ASSERT(vertexData.size() >= (outStreamDesc.stride_ * (i32)meshCluster->vertices_.size())); - auto retVal = Core::Convert(outStreamDesc, inStreamDesc, meshCluster->vertices_.size(), + DBG_ASSERT(vertexData.size() >= (outStreamDesc.stride_ * (i32)mesh->vertices_.size())); + auto retVal = Core::Convert(outStreamDesc, inStreamDesc, mesh->vertices_.size(), numComponents[elementStreamIdx]); DBG_ASSERT_MSG(retVal, "Unable to convert stream."); } @@ -973,6 +962,8 @@ CompressedModel::CompressedModel(const char* sourceFile) streams[vtxStreamIdx].Write(vertexData.data(), vertexData.size()); } } + + indexOffset += mesh->triangles_.size() * 3; } BinaryStream vtxStream; @@ -986,11 +977,11 @@ CompressedModel::CompressedModel(const char* sourceFile) vtxStream.Write(streams[i].Data(), streams[i].Size()); } - vertexBuffer_ = GPU::Manager::CreateBuffer(vertexDesc_, vtxStream.Data(), "clustered_model_vb"); + vertexBuffer_ = GPU::Manager::CreateBuffer(vertexDesc_, vtxStream.Data(), "compressed_model_vb"); indexDesc_.bindFlags_ = GPU::BindFlags::INDEX_BUFFER | GPU::BindFlags::SHADER_RESOURCE; indexDesc_.size_ = numIndices * 4; - indexBuffer_ = GPU::Manager::CreateBuffer(indexDesc_, idxStream.Data(), "clustered_model_ib"); + indexBuffer_ = GPU::Manager::CreateBuffer(indexDesc_, idxStream.Data(), "compressed_model_ib"); GPU::DrawBindingSetDesc dbsDesc; i32 offset = 0; @@ -1009,20 +1000,27 @@ CompressedModel::CompressedModel(const char* sourceFile) dbsDesc.ib_.offset_ = 0; dbsDesc.ib_.size_ = (i32)indexDesc_.size_; dbsDesc.ib_.stride_ = 4; - dbs_ = GPU::Manager::CreateDrawBindingSet(dbsDesc, "clustered_model_dbs"); + dbs_ = GPU::Manager::CreateDrawBindingSet(dbsDesc, "compressed_model_dbs"); techs_.resize(materials_.size()); + compressedTechs_.resize(materials_.size()); for(i32 i = 0; i < materials_.size(); ++i) { materials_[i].WaitUntilReady(); + compressedMaterials_[i].WaitUntilReady(); techs_[i].material_ = materials_[i]; + compressedTechs_[i].material_ = compressedMaterials_[i]; } techDesc_.SetVertexElements(elements_); techDesc_.SetTopology(GPU::TopologyType::TRIANGLE); + compressedTechDesc_.SetVertexElements(elements_); + compressedTechDesc_.SetTopology(GPU::TopologyType::TRIANGLE); + objectBindings_ = Graphics::Shader::CreateSharedBindingSet("ObjectBindings"); + geometryBindings_ = Graphics::Shader::CreateSharedBindingSet("GeometryBindings"); } } @@ -1035,8 +1033,6 @@ CompressedModel::~CompressedModel() void CompressedModel::DrawClusters(Testbed::DrawContext& drawCtx, Testbed::ObjectConstants object) { - return; -#if 0 if(auto event = drawCtx.cmdList_.Eventf(0x0, "CompressedModel")) { i32 numObjects = 1; @@ -1056,28 +1052,35 @@ void CompressedModel::DrawClusters(Testbed::DrawContext& drawCtx, Testbed::Objec { for(i32 meshIdx = 0; meshIdx < meshes_.size(); ++meshIdx) { - auto it = techs_[meshIdx].passIndices_.find(drawCtx.passName_); - if(it != techs_[meshIdx].passIndices_.end()) + auto* techs = &techs_[meshIdx]; + static bool useCompressed = true; + if(useCompressed) + techs = &compressedTechs_[meshIdx]; + + auto it = techs->passIndices_.find(drawCtx.passName_); + if(it != techs->passIndices_.end()) { const auto& mesh = meshes_[meshIdx]; - if(mesh.numClusters_ > 0) - { - auto& tech = techs_[meshIdx].passTechniques_[it->second]; - if(drawCtx.customBindFn_) - drawCtx.customBindFn_(techs_[meshIdx].material_->GetShader(), tech); + auto& tech = techs->passTechniques_[it->second]; + if(drawCtx.customBindFn_) + drawCtx.customBindFn_(techs->material_->GetShader(), tech); - objectBindings_.Set("inObject", GPU::Binding::Buffer(drawCtx.objectSBHandle_, - GPU::Format::INVALID, 0, 1, objectDataSize)); + if(geometryBindings_) + geometryBindings_.Set("geomNormal", GPU::Binding::Texture2D(normalTex_, GPU::Format::R8G8_UNORM, 0, 1)); + + objectBindings_.Set("inObject", GPU::Binding::Buffer(drawCtx.objectSBHandle_, + GPU::Format::INVALID, 0, 1, objectDataSize)); + if(auto geometryBind = drawCtx.shaderCtx_.BeginBindingScope(geometryBindings_)) + { if(auto objectBind = drawCtx.shaderCtx_.BeginBindingScope(objectBindings_)) { GPU::Handle ps; Core::ArrayView pb; if(drawCtx.shaderCtx_.CommitBindings(tech, ps, pb)) { - auto baseCluster = clusters_[meshes_[meshIdx].baseCluster_]; drawCtx.cmdList_.Draw(ps, pb, dbs_, drawCtx.fbs_, drawCtx.drawState_, - GPU::PrimitiveTopology::TRIANGLE_LIST, baseCluster.baseIndex_, 0, - mesh.numClusters_ * baseCluster.numIndices_, 0, 1); + GPU::PrimitiveTopology::TRIANGLE_LIST, 0, 0, + mesh.numIndices_, 0, 1); } } } @@ -1085,5 +1088,4 @@ void CompressedModel::DrawClusters(Testbed::DrawContext& drawCtx, Testbed::Objec } } } -#endif } diff --git a/apps/testbed/compressed_model.h b/apps/testbed/compressed_model.h index f7f8273..49af162 100644 --- a/apps/testbed/compressed_model.h +++ b/apps/testbed/compressed_model.h @@ -18,22 +18,13 @@ class CompressedModel struct Mesh { - i32 baseCluster_ = 0; - i32 numClusters_ = 0; - }; - - struct MeshCluster - { - i32 meshIdx_ = 0; - i32 baseDrawArg_ = 0; + Math::AABB bounds_; i32 baseVertex_ = 0; i32 baseIndex_ = 0; i32 numIndices_ = 0; }; Core::Vector meshes_; - Core::Vector clusters_; - Core::Vector clusterBounds_; GPU::BufferDesc vertexDesc_; GPU::BufferDesc indexDesc_; @@ -50,11 +41,15 @@ class CompressedModel GPU::Handle dbs_; Core::Vector materials_; + Core::Vector compressedMaterials_; Graphics::ShaderBindingSet objectBindings_; + Graphics::ShaderBindingSet geometryBindings_; Graphics::ShaderTechniqueDesc techDesc_; + Graphics::ShaderTechniqueDesc compressedTechDesc_; Core::Vector techs_; + Core::Vector compressedTechs_; bool enableCulling_ = true; }; diff --git a/apps/testbed/test_entry.cpp b/apps/testbed/test_entry.cpp index b0f2ecb..eaf657d 100644 --- a/apps/testbed/test_entry.cpp +++ b/apps/testbed/test_entry.cpp @@ -951,9 +951,10 @@ void Loop(const Core::CommandLine& cmdLine) } for(auto& techs : testCompressedModel->techs_) - { forwardPipeline.CreateTechniques(techs.material_, testCompressedModel->techDesc_, techs); - } + + for(auto& techs : testCompressedModel->compressedTechs_) + forwardPipeline.CreateTechniques(techs.material_, testCompressedModel->compressedTechDesc_, techs); } diff --git a/res/default_compressed.material b/res/default_compressed.material new file mode 100644 index 0000000..cdbee17 --- /dev/null +++ b/res/default_compressed.material @@ -0,0 +1,3 @@ +{ + "shader" : "shaders/default_compressed.esf" +} diff --git a/res/default_compressed.material.metadata b/res/default_compressed.material.metadata new file mode 100644 index 0000000..1b54f5d --- /dev/null +++ b/res/default_compressed.material.metadata @@ -0,0 +1,6 @@ +{ + "$internal" : { + "dependencies" : [ "shaders/default_compressed.esf" ], + "outputs" : [ "../../../../.converter_output/default_compressed.material.converted" ] + } +} diff --git a/res/shaders/base_geometry.esh b/res/shaders/base_geometry.esh index b00c3ac..93f2e0a 100644 --- a/res/shaders/base_geometry.esh +++ b/res/shaders/base_geometry.esh @@ -60,6 +60,7 @@ struct VertexData #endif uint instanceID; + uint vertexID; }; struct PixelData @@ -147,13 +148,14 @@ float3 CalculateNormal(in PixelData pixData) return v_normal; } -VS_OUT vs_position(in float3 _in : POSITION, uint _id : SV_INSTANCEID) +VS_OUT vs_position(in float3 _in : POSITION, uint _id : SV_INSTANCEID, uint _vtx : SV_VERTEXID) { Object o = GetObjectUniforms(inObject, _id); VertexData vtxData = (VertexData)0; vtxData.input.position = _in; vtxData.instanceID = _id; + vtxData.vertexID = _vtx; vtxData.positionWS = GetPositionWS(o, _in); vtxData.positionVS = GetPositionVS(viewParams, vtxData.positionWS.xyz); vtxData.positionCS = GetPositionCS(viewParams, vtxData.positionWS.xyz); @@ -178,13 +180,14 @@ VS_OUT vs_position(in float3 _in : POSITION, uint _id : SV_INSTANCEID) return outVtx; } -VS_OUT vs_main(in VS_IN _in, uint _id : SV_INSTANCEID) +VS_OUT vs_main(in VS_IN _in, uint _id : SV_INSTANCEID, uint _vtx : SV_VERTEXID) { Object o = GetObjectUniforms(inObject, _id); VertexData vtxData = (VertexData)0; vtxData.input = _in; vtxData.instanceID = _id; + vtxData.vertexID = _vtx; vtxData.positionWS = GetPositionWS(o, _in.position); vtxData.positionVS = GetPositionVS(viewParams, vtxData.positionWS.xyz); vtxData.positionCS = GetPositionCS(viewParams, vtxData.positionWS.xyz); @@ -200,9 +203,10 @@ VS_OUT vs_main(in VS_IN _in, uint _id : SV_INSTANCEID) vtxData.texcoord0 = _in.texcoord0; #endif - if(ShadeVertex(PASS_DEPTH_PREPASS, o, vtxData)) + if(ShadeVertex(PASS_FORWARD, o, vtxData)) { vtxData.positionCS = GetPositionCS(viewParams, vtxData.positionWS.xyz); + vtxData.normalVS = GetNormalVS(viewParams, vtxData.normalWS.xyz); } VS_OUT outVtx = (VS_OUT)0; diff --git a/res/shaders/default_compressed.esf b/res/shaders/default_compressed.esf new file mode 100644 index 0000000..e5a30bb --- /dev/null +++ b/res/shaders/default_compressed.esf @@ -0,0 +1,70 @@ +#include "base_geometry.esh" + +[shared] +[frequency(MEDIUM)] +BindingSet GeometryBindings +{ + Texture2D geomNormal; +}; + + +float2 EncodeSMT(float3 n) +{ + float2 n2 = float2(n.x, n.y); + float2 enc = normalize(n2) * sqrt(-n.z * 0.5f + 0.5f); + enc = enc * 0.5f + float2(0.5f, 0.5f); + return enc; +} + +float3 DecodeSMT(float2 enc) +{ + float4 nn = float4(enc, 0, 0) * float4(2, 2, 0, 0) + float4(-1.0f, -1.0f, 1.0f, -1.0f); + float3 n1 = float3(nn.x, nn.y, nn.z); + float3 n2 = float3(-nn.x, -nn.y, -nn.w); + float l = dot(n1, n2); + nn.z = l; + nn.x *= sqrt(l); + nn.y *= sqrt(l); + return float3(nn.x, nn.y, nn.z) * 2.0f + float3(0.0f, 0.0f, -1.0f); +} + +uint ShadeVertex(uniform int passID, in Object obj, inout VertexData vtxData) +{ + uint w, h; + geomNormal.GetDimensions(w, h); + + uint x = vtxData.vertexID % w; + uint y = vtxData.vertexID / w; + + vtxData.normalWS = DecodeSMT(geomNormal[int2(x, y)].xy); + vtxData.normalWS = normalize(vtxData.normalWS); + + return VTX_CHANGED_NORMAL; +} + +uint ShadePixel(uniform int passID, inout PixelData pixData) +{ + switch(passID) + { + case PASS_DEPTH_PREPASS: + { + return PIX_DEFAULT; + } + + case PASS_SHADOW: + { + return PIX_DEFAULT; + } + + case PASS_FORWARD: + { + pixData.color.rgb = float4(1.0, 1.0, 1.0, 1.0); + pixData.roughness = 0.5; + pixData.metallic = 0.0; + pixData.specular = DIELECTRIC_F0; + return PIX_LIGHTING; + } + } + + return PIX_DEFAULT; +} diff --git a/src/graphics/converters/converter_shader.cpp b/src/graphics/converters/converter_shader.cpp index 03260d1..e7c2524 100644 --- a/src/graphics/converters/converter_shader.cpp +++ b/src/graphics/converters/converter_shader.cpp @@ -27,8 +27,8 @@ #define DEBUG_DUMP_SHADERS 1 -#define DUMP_ESF_PATH "D:\\tmp.esf" -#define DUMP_HLSL_PATH "D:\\shader_dump\\%s-%s.hlsl" +#define DUMP_ESF_PATH "tmp.esf" +#define DUMP_HLSL_PATH "shader_dump\\%s-%s.hlsl" namespace { @@ -114,6 +114,24 @@ namespace Graphics::ShaderBackendMetadata backendMetadata; node->Visit(&backendMetadata); + // Get all technique entrypoints. + Graphics::FunctionExports functionExports; + for(const auto& tech : backendMetadata.GetTechniques()) + { + if(tech.vs_.size() > 0) + functionExports.push_back(tech.vs_); + if(tech.hs_.size() > 0) + functionExports.push_back(tech.hs_); + if(tech.ds_.size() > 0) + functionExports.push_back(tech.ds_); + if(tech.hs_.size() > 0) + functionExports.push_back(tech.hs_); + if(tech.ps_.size() > 0) + functionExports.push_back(tech.ps_); + if(tech.cs_.size() > 0) + functionExports.push_back(tech.cs_); + } + // Gather all unique shaders referenced by techniques. const auto& techniques = backendMetadata.GetTechniques(); Core::Array, (i32)GPU::ShaderType::MAX> shaders; @@ -164,7 +182,7 @@ namespace outCompileOutput.clear(); // Generate HLSL for the whole ESF. - Graphics::ShaderBackendHLSL backendHLSL(bindingMap, true); + Graphics::ShaderBackendHLSL backendHLSL(bindingMap, functionExports, true); node->Visit(&backendHLSL); #if DEBUG_DUMP_SHADERS diff --git a/src/graphics/converters/shader_backend_hlsl.cpp b/src/graphics/converters/shader_backend_hlsl.cpp index cd99ee8..20fd582 100644 --- a/src/graphics/converters/shader_backend_hlsl.cpp +++ b/src/graphics/converters/shader_backend_hlsl.cpp @@ -22,8 +22,9 @@ namespace namespace Graphics { - ShaderBackendHLSL::ShaderBackendHLSL(const BindingMap& bindingMap, bool autoReg) + ShaderBackendHLSL::ShaderBackendHLSL(const BindingMap& bindingMap, const FunctionExports& functionExports, bool autoReg) : bindingMap_(bindingMap) + , functionExports_(functionExports) , autoReg_(autoReg) { for(const char* attribute : HLSL_ATTRIBUTES) @@ -41,6 +42,7 @@ namespace Graphics for(auto* intNode : node->variables_) intNode->Visit(this); + bool writeUsed = bindingMap_.size() != 0; // Write out generated shader. Write("////////////////////////////////////////////////////////////////////////////////////////////////////"); @@ -75,7 +77,7 @@ namespace Graphics NextLine(); for(auto* intNode : samplerStates_) - if(bindingMap_.size() == 0 || bindingMap_.find(intNode->name_) != bindingMap_.end()) + if(!writeUsed || bindingMap_.find(intNode->name_) != bindingMap_.end()) WriteVariable(intNode); NextLine(); @@ -85,16 +87,72 @@ namespace Graphics NextLine(); for(auto* intNode : bindingSets_) - WriteBindingSet(intNode); + WriteBindingSet(intNode, false); NextLine(); + if(writeUsed) + { + Write("////////////////////////////////////////////////////////////////////////////////////////////////////"); + NextLine(); + Write("// unused resources (used to keep the compiler happy)"); + NextLine(); + + autoReg_ = false; + + for(auto* intNode : samplerStates_) + if(bindingMap_.find(intNode->name_) == bindingMap_.end()) + WriteVariable(intNode); + NextLine(); + + for(auto* intNode : bindingSets_) + WriteBindingSet(intNode, true); + NextLine(); + } + Write("////////////////////////////////////////////////////////////////////////////////////////////////////"); NextLine(); Write("// functions"); NextLine(); +#if 0 // WIP. + // Determine if a function is referenced. This is a bit overkill, as it's just a text search. + auto IsFunctionReferenced = [this](AST::NodeDeclaration* fn) + { + for(auto* refFunc : refFunctions_) + { + if(refFunc->value_ && refFunc->value_->data_.size() > 0) + { + if(refFunc->value_->data_.find(fn->name_) != Core::String::npos) + { + return true; + } + } + } + return false; + }; + + // Reference exports. + for(const auto& functionExport : functionExports_) + { + if(auto* fn = node->FindFunction(functionExport.c_str())) + { + refFunctions_.insert(fn); + } + } + + // Find all referenced functions. for(auto* intNode : node->functions_) + { + if(IsFunctionReferenced(intNode)) + { + refFunctions_.insert(intNode); + } + } +#endif + for(auto* intNode : node->functions_) + { WriteFunction(intNode); + } NextLine(); return false; @@ -332,7 +390,7 @@ namespace Graphics NextLine(); } - void ShaderBackendHLSL::WriteBindingSet(AST::NodeStruct* node) + void ShaderBackendHLSL::WriteBindingSet(AST::NodeStruct* node, bool writeOnlyUnused) { Write("// - %s", node->name_.c_str()); NextLine(); @@ -341,7 +399,7 @@ namespace Graphics for(auto* member : node->type_->members_) writeBindingSet |= (bindingMap_.size() == 0 || bindingMap_.find(member->name_) != bindingMap_.end()); - if(writeBindingSet) + if((writeBindingSet && !writeOnlyUnused) || (!writeBindingSet && writeOnlyUnused)) { for(auto* member : node->type_->members_) WriteVariable(member); diff --git a/src/graphics/converters/shader_backend_hlsl.h b/src/graphics/converters/shader_backend_hlsl.h index f83b5fb..2ca3a15 100644 --- a/src/graphics/converters/shader_backend_hlsl.h +++ b/src/graphics/converters/shader_backend_hlsl.h @@ -2,14 +2,24 @@ #include "graphics/converters/shader_ast.h" + +namespace Core +{ + inline u32 Hash(u32 input, Graphics::AST::NodeDeclaration* node) + { + return Core::HashCRC32(input, &node, sizeof(node)); + } +} // namespace Core + namespace Graphics { using BindingMap = Core::Map; + using FunctionExports = Core::Vector; class ShaderBackendHLSL : public AST::IVisitor { public: - ShaderBackendHLSL(const BindingMap& bindingMap, bool autoReg); + ShaderBackendHLSL(const BindingMap& bindingMap, const FunctionExports& functionExports, bool autoReg); virtual ~ShaderBackendHLSL(); bool VisitEnter(AST::NodeShaderFile* node) override; void VisitExit(AST::NodeShaderFile* node) override; @@ -35,7 +45,7 @@ namespace Graphics void VisitExit(AST::NodeMemberValue* node) override; void WriteStruct(AST::NodeStruct* node); - void WriteBindingSet(AST::NodeStruct* node); + void WriteBindingSet(AST::NodeStruct* node, bool writeOnlyUnused); void WriteFunction(AST::NodeDeclaration* node); void WriteVariable(AST::NodeDeclaration* node); void WriteParameter(AST::NodeDeclaration* node); @@ -49,6 +59,8 @@ namespace Graphics bool IsInternal(AST::Node* node, const char* internalType = nullptr) const; const BindingMap& bindingMap_; + const FunctionExports& functionExports_; + bool autoReg_ = false; bool isNewLine_ = false; @@ -63,6 +75,9 @@ namespace Graphics Core::String outCode_; + /// Referenced functions. + Core::Set refFunctions_; + Core::Vector structs_; Core::Vector bindingSets_; diff --git a/src/graphics/private/shader.cpp b/src/graphics/private/shader.cpp index c80a952..e3e74e4 100644 --- a/src/graphics/private/shader.cpp +++ b/src/graphics/private/shader.cpp @@ -741,6 +741,9 @@ namespace Graphics ShaderContext::ScopedBinding ShaderContext::BeginBindingScope(const ShaderBindingSet& bindingSet) { + if(!bindingSet) + return ShaderContext::ScopedBinding(*this, -1); + i32 idx = bindingSet.impl_->idx_; DBG_ASSERT(impl_->bindingSets_[idx] == nullptr); impl_->bindingSets_[idx] = bindingSet.impl_;