diff --git a/Source/Core/ShaderConductor.cpp b/Source/Core/ShaderConductor.cpp index 62a2b087..30abd982 100644 --- a/Source/Core/ShaderConductor.cpp +++ b/Source/Core/ShaderConductor.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -371,6 +372,7 @@ namespace #ifdef LLVM_ON_WIN32 Reflection MakeDxilReflection(IDxcBlob* dxilBlob); #endif + Reflection MakeSpirVReflection(const spirv_cross::Compiler& compiler); void ConvertDxcResult(Compiler::ResultDesc& result, IDxcOperationResult* dxcResult, ShadingLanguage targetLanguage, bool asModule, bool needReflection) @@ -406,7 +408,7 @@ namespace #ifdef LLVM_ON_WIN32 if ((targetLanguage == ShadingLanguage::Dxil) && !asModule) { - // Gather reflection information only for ShadingLanguage::Dxil + // Gather reflection information only for ShadingLanguage::Dxil. SPIR-V reflection is gathered when cross-compiling. result.reflection = MakeDxilReflection(program); } #else @@ -838,7 +840,10 @@ namespace const std::string targetStr = compiler->compile(); ret.target.Reset(targetStr.data(), static_cast(targetStr.size())); ret.hasError = false; - ret.reflection = std::move(binaryResult.reflection); + if (options.needReflection) + { + ret.reflection = MakeSpirVReflection(*compiler); + } } catch (spirv_cross::CompilerError& error) { @@ -1075,6 +1080,108 @@ namespace ShaderConductor } #endif + VariableTypeImpl(const spirv_cross::Compiler& compiler, const spirv_cross::SPIRType& spirvParentReflectionType, + uint32_t variableIndex, const spirv_cross::SPIRType& spirvReflectionType) + { + switch (spirvReflectionType.basetype) + { + case spirv_cross::SPIRType::Boolean: + m_type = DataType::Bool; + m_name = "bool"; + break; + case spirv_cross::SPIRType::Int: + m_type = DataType::Int; + m_name = "int"; + break; + case spirv_cross::SPIRType::UInt: + m_type = DataType::Uint; + m_name = "uint"; + break; + case spirv_cross::SPIRType::Float: + m_type = DataType::Float; + m_name = "float"; + break; + + case spirv_cross::SPIRType::Half: + m_type = DataType::Half; + m_name = "half"; + break; + case spirv_cross::SPIRType::Short: + m_type = DataType::Int16; + m_name = "int16_t"; + break; + case spirv_cross::SPIRType::UShort: + m_type = DataType::Uint16; + m_name = "uint16_t"; + break; + + case spirv_cross::SPIRType::Struct: + m_type = DataType::Struct; + m_name = compiler.get_name(spirvReflectionType.self); + + for (uint32_t memberIndex = 0; memberIndex < spirvReflectionType.member_types.size(); ++memberIndex) + { + VariableDesc member{}; + + const std::string& memberName = compiler.get_member_name(spirvReflectionType.self, memberIndex); + std::strncpy(member.name, memberName.c_str(), sizeof(member.name)); + + member.type = Make(compiler, spirvReflectionType, memberIndex, compiler.get_type(spirvReflectionType.member_types[memberIndex])); + + member.offset = compiler.type_struct_member_offset(spirvReflectionType, memberIndex); + member.size = static_cast(compiler.get_declared_struct_member_size(spirvReflectionType, memberIndex)); + + m_members.emplace_back(std::move(member)); + } + break; + + case spirv_cross::SPIRType::Void: + m_type = DataType::Void; + m_name = "void"; + break; + + default: + llvm_unreachable("Unsupported variable type."); + break; + } + + if (spirvReflectionType.columns == 1) + { + if (spirvReflectionType.vecsize > 1) + { + m_name += std::to_string(spirvReflectionType.vecsize); + } + } + else + { + m_name += std::to_string(spirvReflectionType.columns) + 'x' + std::to_string(spirvReflectionType.vecsize); + } + + m_rows = spirvReflectionType.columns; + m_columns = spirvReflectionType.vecsize; + if (compiler.has_member_decoration(spirvParentReflectionType.self, variableIndex, spv::DecorationColMajor)) + { + std::swap(m_rows, m_columns); + } + if (spirvReflectionType.array.empty()) + { + m_elements = 0; + } + else + { + m_elements = spirvReflectionType.array[0]; + } + + if (!spirvReflectionType.array.empty()) + { + m_elementStride = compiler.type_struct_member_array_stride(spirvParentReflectionType, variableIndex); + } + else + { + m_elementStride = 0; + } + } + const char* Name() const noexcept { return m_name.c_str(); @@ -1142,6 +1249,14 @@ namespace ShaderConductor } #endif + static VariableType Make(const spirv_cross::Compiler& compiler, const spirv_cross::SPIRType& spirvParentReflectionType, uint32_t variableIndex, + const spirv_cross::SPIRType& spirvReflectionType) + { + VariableType ret; + ret.m_impl = new VariableTypeImpl(compiler, spirvParentReflectionType, variableIndex, spirvReflectionType); + return ret; + } + private: std::string m_name; DataType m_type; @@ -1279,6 +1394,31 @@ namespace ShaderConductor } #endif + explicit ConstantBufferImpl(const spirv_cross::Compiler& compiler, const spirv_cross::Resource& resource) + { + const auto& cbufferType = compiler.get_type(resource.type_id); + + m_name = compiler.get_name(resource.id); + + for (uint32_t variableIndex = 0; variableIndex < cbufferType.member_types.size(); ++variableIndex) + { + VariableDesc variableDesc{}; + + const std::string& varName = compiler.get_member_name(cbufferType.self, variableIndex); + std::strncpy(variableDesc.name, varName.c_str(), sizeof(variableDesc.name)); + + variableDesc.type = VariableType::VariableTypeImpl::Make(compiler, cbufferType, variableIndex, + compiler.get_type(cbufferType.member_types[variableIndex])); + + variableDesc.offset = compiler.type_struct_member_offset(cbufferType, variableIndex); + variableDesc.size = static_cast(compiler.get_declared_struct_member_size(cbufferType, variableIndex)); + + m_variableDescs.emplace_back(std::move(variableDesc)); + } + + m_size = static_cast(compiler.get_declared_struct_size(cbufferType)); + } + const char* Name() const noexcept { return m_name.c_str(); @@ -1326,6 +1466,13 @@ namespace ShaderConductor } #endif + static ConstantBuffer Make(const spirv_cross::Compiler& compiler, const spirv_cross::Resource& resource) + { + ConstantBuffer ret; + ret.m_impl = new ConstantBufferImpl(compiler, resource); + return ret; + } + private: std::string m_name; uint32_t m_size; @@ -1897,6 +2044,374 @@ namespace ShaderConductor } #endif + explicit ReflectionImpl(const spirv_cross::Compiler& compiler) + { + spirv_cross::ShaderResources resources = compiler.get_shader_resources(); + + for (const auto& resource : resources.uniform_buffers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::ConstantBuffer; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + + m_constantBuffers.emplace_back(ConstantBuffer::ConstantBufferImpl::Make(compiler, resource)); + } + + for (const auto& resource : resources.storage_buffers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + + const spirv_cross::Bitset& typeFlags = compiler.get_decoration_bitset(compiler.get_type(resource.type_id).self); + const auto& type = compiler.get_type(resource.type_id); + + const bool ssboBlock = type.storage == spv::StorageClassStorageBuffer || + (type.storage == spv::StorageClassUniform && typeFlags.get(spv::DecorationBufferBlock)); + if (ssboBlock) + { + spirv_cross::Bitset buffer_flags = compiler.get_buffer_block_flags(resource.id); + if (buffer_flags.get(spv::DecorationNonWritable)) + { + reflectionDesc.type = ShaderResourceType::ShaderResourceView; + } + else + { + reflectionDesc.type = ShaderResourceType::UnorderedAccessView; + } + } + else + { + reflectionDesc.type = ShaderResourceType::ShaderResourceView; + } + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.storage_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::UnorderedAccessView; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.separate_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::Texture; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.separate_samplers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::Sampler; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + uint32_t combinedBinding = 0; + for (const auto& resource : resources.sampled_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.bindPoint = combinedBinding; + reflectionDesc.type = ShaderResourceType::Texture; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + ++combinedBinding; + } + + for (const auto& inputParam : resources.builtin_inputs) + { + const std::string semantic = this->ExtractBuiltInemantic(inputParam.builtin); + if (!semantic.empty()) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, inputParam.resource, semantic); + + const auto& type = compiler.get_type(inputParam.resource.type_id); + switch (inputParam.builtin) + { + case spv::BuiltInTessLevelInner: + case spv::BuiltInTessLevelOuter: + for (uint32_t patchConstantParamIndex = 0; patchConstantParamIndex < type.array[0]; ++patchConstantParamIndex) + { + if (inputParam.builtin == spv::BuiltInTessLevelOuter) + { + paramDesc.semanticIndex = patchConstantParamIndex; + paramDesc.mask = ComponentMask::W; + } + else + { + paramDesc.semanticIndex = 0; + paramDesc.mask = ComponentMask::X; + } + + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + break; + + default: + m_inputParams.emplace_back(std::move(paramDesc)); + break; + } + } + } + + for (const auto& inputParam : resources.stage_inputs) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, inputParam); + + if (compiler.get_decoration(inputParam.id, spv::DecorationPatch)) + { + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + else + { + m_inputParams.emplace_back(std::move(paramDesc)); + } + } + + for (const auto& outputParam : resources.builtin_outputs) + { + const std::string semantic = this->ExtractBuiltInemantic(outputParam.builtin); + if (!semantic.empty()) + { + SignatureParameterDesc paramDesc{}; + const auto& type = compiler.get_type(outputParam.resource.type_id); + this->ExtractParameter(paramDesc, compiler, outputParam.resource, semantic); + + switch (type.basetype) + { + case spirv_cross::SPIRType::UInt: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case spirv_cross::SPIRType::Int: + paramDesc.componentType = VariableType::DataType::Int; + break; + case spirv_cross::SPIRType::Float: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported parameter component type."); + break; + } + + if (type.vecsize > 0) + { + paramDesc.mask = ComponentMask::X; + } + if (type.vecsize > 1) + { + paramDesc.mask |= ComponentMask::Y; + } + if (type.vecsize > 2) + { + paramDesc.mask |= ComponentMask::Z; + } + if (type.vecsize > 3) + { + paramDesc.mask |= ComponentMask::W; + } + + switch (outputParam.builtin) + { + case spv::BuiltInTessLevelInner: + case spv::BuiltInTessLevelOuter: + for (uint32_t patchConstantParamIndex = 0; patchConstantParamIndex < type.array[0]; ++patchConstantParamIndex) + { + paramDesc.semanticIndex = patchConstantParamIndex; + + if (outputParam.builtin == spv::BuiltInTessLevelOuter) + { + paramDesc.mask = ComponentMask::W; + } + else + { + paramDesc.mask = ComponentMask::X; + } + + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + break; + + default: + m_outputParams.emplace_back(std::move(paramDesc)); + break; + } + } + } + + for (const auto& outputParam : resources.stage_outputs) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, outputParam); + + m_outputParams.emplace_back(std::move(paramDesc)); + } + + m_gsHSInputPrimitive = Reflection::PrimitiveTopology::Undefined; + m_gsOutputTopology = Reflection::PrimitiveTopology::Undefined; + m_gsMaxNumOutputVertices = 0; + m_gsNumInstances = 0; + m_hsOutputPrimitive = Reflection::TessellatorOutputPrimitive::Undefined; + m_hsPartitioning = Reflection::TessellatorPartitioning::Undefined; + m_hSDSTessellatorDomain = Reflection::TessellatorDomain::Undefined; + m_hsDSNumCtrlPoints = 0; + m_csBlockSizeX = m_csBlockSizeY = m_csBlockSizeZ = 0; + + const auto& modes = compiler.get_execution_mode_bitset(); + switch (compiler.get_execution_model()) + { + case spv::ExecutionModelTessellationControl: + if (modes.get(spv::ExecutionModeOutputVertices)) + { + m_hsDSNumCtrlPoints = compiler.get_execution_mode_argument(spv::ExecutionModeOutputVertices, 0); + switch (m_hsDSNumCtrlPoints) + { + case 2: + m_hSDSTessellatorDomain = TessellatorDomain::Line; + break; + case 3: + m_hSDSTessellatorDomain = TessellatorDomain::Triangle; + break; + case 4: + m_hSDSTessellatorDomain = TessellatorDomain::Quad; + break; + + default: + break; + } + } + + if (modes.get(spv::ExecutionModeInputPoints)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_1_CtrlPoint; + } + else if (modes.get(spv::ExecutionModeInputLines)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_2_CtrlPoint; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_3_CtrlPoint; + } + + if (modes.get(spv::ExecutionModeVertexOrderCw)) + { + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCW; + } + else if (modes.get(spv::ExecutionModeVertexOrderCcw)) + { + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCCW; + } + + if (modes.get(spv::ExecutionModeSpacingEqual)) + { + m_hsPartitioning = TessellatorPartitioning::Integer; + } + else if (modes.get(spv::ExecutionModeSpacingFractionalOdd)) + { + m_hsPartitioning = TessellatorPartitioning::FractionalOdd; + } + else if (modes.get(spv::ExecutionModeSpacingFractionalOdd)) + { + m_hsPartitioning = TessellatorPartitioning::FractionalEven; + } + break; + + case spv::ExecutionModelTessellationEvaluation: + if (modes.get(spv::ExecutionModeIsolines)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Line; + m_hsDSNumCtrlPoints = 2; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Triangle; + m_hsDSNumCtrlPoints = 3; + } + else if (modes.get(spv::ExecutionModeQuads)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Quad; + m_hsDSNumCtrlPoints = 4; + } + break; + + case spv::ExecutionModelGeometry: + if (modes.get(spv::ExecutionModeOutputVertices)) + { + m_gsMaxNumOutputVertices = compiler.get_execution_mode_argument(spv::ExecutionModeOutputVertices, 0); + } + + if (modes.get(spv::ExecutionModeInvocations)) + { + m_gsNumInstances = compiler.get_execution_mode_argument(spv::ExecutionModeInvocations, 0); + } + + if (modes.get(spv::ExecutionModeInputPoints)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Points; + } + else if (modes.get(spv::ExecutionModeInputLines)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Lines; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Triangles; + } + else if (modes.get(spv::ExecutionModeInputLinesAdjacency)) + { + m_gsHSInputPrimitive = PrimitiveTopology::LinesAdj; + } + else if (modes.get(spv::ExecutionModeInputTrianglesAdjacency)) + { + m_gsHSInputPrimitive = PrimitiveTopology::TrianglesAdj; + } + + if (modes.get(spv::ExecutionModeOutputPoints)) + { + m_gsOutputTopology = PrimitiveTopology::Points; + } + else if (modes.get(spv::ExecutionModeOutputLineStrip)) + { + m_gsOutputTopology = PrimitiveTopology::LineStrip; + } + else if (modes.get(spv::ExecutionModeOutputTriangleStrip)) + { + m_gsOutputTopology = PrimitiveTopology::TriangleStrip; + } + break; + + case spv::ExecutionModelGLCompute: + { + spirv_cross::SpecializationConstant spec_x, spec_y, spec_z; + compiler.get_work_group_size_specialization_constants(spec_x, spec_y, spec_z); + + m_csBlockSizeX = spec_x.id != spirv_cross::ID(0) ? spec_x.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 0); + m_csBlockSizeY = spec_y.id != spirv_cross::ID(0) ? spec_y.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 1); + m_csBlockSizeZ = spec_z.id != spirv_cross::ID(0) ? spec_z.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 2); + break; + } + + default: + break; + } + } + uint32_t NumResources() const noexcept { return static_cast(m_resourceDescs.size()); @@ -2062,6 +2577,149 @@ namespace ShaderConductor } #endif + static Reflection Make(const spirv_cross::Compiler& compiler) + { + Reflection ret; + ret.m_impl = new ReflectionImpl(compiler); + return ret; + } + + private: + static std::string ExtractBuiltInemantic(spv::BuiltIn builtin) + { + std::string semantic; + switch (builtin) + { + case spv::BuiltInPosition: + case spv::BuiltInFragCoord: + semantic = "SV_Position"; + break; + + case spv::BuiltInFragDepth: + semantic = "SV_Depth"; + break; + + case spv::BuiltInVertexId: + case spv::BuiltInVertexIndex: + semantic = "SV_VertexID"; + break; + + case spv::BuiltInInstanceId: + case spv::BuiltInInstanceIndex: + semantic = "SV_InstanceID"; + break; + + case spv::BuiltInSampleId: + semantic = "SV_SampleIndex"; + break; + + case spv::BuiltInSampleMask: + semantic = "SV_Coverage"; + break; + + case spv::BuiltInTessLevelInner: + semantic = "SV_InsideTessFactor"; + break; + + case spv::BuiltInTessLevelOuter: + semantic = "SV_TessFactor"; + break; + + case spv::BuiltInGlobalInvocationId: + case spv::BuiltInLocalInvocationId: + case spv::BuiltInLocalInvocationIndex: + case spv::BuiltInWorkgroupId: + case spv::BuiltInFrontFacing: + case spv::BuiltInInvocationId: + case spv::BuiltInPrimitiveId: + case spv::BuiltInTessCoord: + break; + + default: + llvm_unreachable("Unsupported builtin."); + } + return semantic; + } + + static void ExtractReflection(ResourceDesc& reflectionDesc, const spirv_cross::Compiler& compiler, spirv_cross::ID id) + { + const uint32_t descSet = compiler.get_decoration(id, spv::DecorationDescriptorSet); + const uint32_t binding = compiler.get_decoration(id, spv::DecorationBinding); + + const std::string& res_name = compiler.get_name(id); + std::strncpy(reflectionDesc.name, res_name.c_str(), sizeof(reflectionDesc.name)); + reflectionDesc.space = descSet; + reflectionDesc.bindPoint = binding; + reflectionDesc.bindCount = 1; + } + + static void ExtractParameter(SignatureParameterDesc& paramDesc, const spirv_cross::Compiler& compiler, + const spirv_cross::Resource& resource, const std::string& semantic) + { + paramDesc.semanticIndex = 0; + for (auto iter = semantic.rbegin(); iter != semantic.rend(); ++iter) + { + if (!std::isdigit(*iter)) + { + const int sep = static_cast(std::distance(semantic.begin(), iter.base())); + const std::string indexPart = semantic.substr(sep); + if (indexPart.empty()) + { + paramDesc.semanticIndex = 0; + } + else + { + paramDesc.semanticIndex = std::atoi(indexPart.c_str()); + } + std::strncpy(paramDesc.semantic, semantic.c_str(), std::min(sep, sizeof(paramDesc.semantic))); + break; + } + } + + const auto& type = compiler.get_type(resource.type_id); + switch (type.basetype) + { + case spirv_cross::SPIRType::UInt: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case spirv_cross::SPIRType::Int: + paramDesc.componentType = VariableType::DataType::Int; + break; + case spirv_cross::SPIRType::Float: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported parameter component type."); + break; + } + + if (type.vecsize > 0) + { + paramDesc.mask = ComponentMask::X; + } + if (type.vecsize > 1) + { + paramDesc.mask |= ComponentMask::Y; + } + if (type.vecsize > 2) + { + paramDesc.mask |= ComponentMask::Z; + } + if (type.vecsize > 3) + { + paramDesc.mask |= ComponentMask::W; + } + + paramDesc.location = compiler.get_decoration(resource.id, spv::DecorationLocation); + } + + static void ExtractParameter(SignatureParameterDesc& paramDesc, const spirv_cross::Compiler& compiler, + const spirv_cross::Resource& resource) + { + ExtractParameter(paramDesc, compiler, resource, compiler.get_name(resource.id)); + } + private: std::vector m_resourceDescs; std::vector m_constantBuffers; @@ -2440,6 +3098,11 @@ namespace return Reflection::ReflectionImpl::Make(dxilBlob); } #endif + + Reflection MakeSpirVReflection(const spirv_cross::Compiler& compiler) + { + return Reflection::ReflectionImpl::Make(compiler); + } } // namespace #ifdef _WIN32 diff --git a/Source/Tests/ReflectionTest.cpp b/Source/Tests/ReflectionTest.cpp index 3d71f574..a4db155a 100644 --- a/Source/Tests/ReflectionTest.cpp +++ b/Source/Tests/ReflectionTest.cpp @@ -36,6 +36,17 @@ using namespace ShaderConductor; namespace { + struct ReflectionTestTarget + { + Compiler::TargetDesc target; + bool isText; + std::string inputParamPrefix; + std::string outputParamPrefix; + }; + + const ReflectionTestTarget testTargets[] = {{{ShadingLanguage::Dxil, ""}, false, "", ""}, + {{ShadingLanguage::Glsl, "410"}, true, "in_var_", "out_var_"}}; + TEST(ReflectionTest, VertexShader) { const std::string fileName = TEST_DATA_DIR "Input/Transform_VS.hlsl"; @@ -46,266 +57,99 @@ namespace Compiler::Options options{}; options.needReflection = true; - const auto result = - Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::VertexShader}, options, {ShadingLanguage::Dxil, ""}); - - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); - - if (!result.reflection.Valid()) - { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } - - EXPECT_EQ(result.reflection.NumInputParameters(), 1U); + for (const auto& testTarget : testTargets) { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "POSITION"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 0U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); - } - EXPECT_EQ(result.reflection.InputParameter(1), nullptr); - - EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); - { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 0U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); - } - EXPECT_EQ(result.reflection.OutputParameter(1), nullptr); + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::VertexShader}, options, testTarget.target); - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); - EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); - - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); - - EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); - - EXPECT_EQ(result.reflection.NumResources(), 1U); - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbVS"); - EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); - EXPECT_EQ(result.reflection.ResourceByIndex(1), nullptr); - - const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); - EXPECT_NE(cbuffer, nullptr); - EXPECT_STREQ(cbuffer->Name(), "cbVS"); - EXPECT_EQ(cbuffer->Size(), 64U); - - EXPECT_EQ(cbuffer->NumVariables(), 1U); + if (!result.reflection.Valid()) { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "wvp"); - EXPECT_STREQ(variable->type.Name(), "float4x4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 4U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 64U); + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); } - EXPECT_EQ(result.reflection.ConstantBufferByIndex(1), nullptr); - } - } - - TEST(ReflectionTest, HullShader) - { - const std::string fileName = TEST_DATA_DIR "Input/DetailTessellation_HS.hlsl"; - std::vector input = LoadFile(fileName, true); - const std::string source = std::string(reinterpret_cast(input.data()), input.size()); - - Compiler::Options options{}; - options.needReflection = true; - - const auto result = - Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::HullShader}, options, {ShadingLanguage::Dxil, ""}); - - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); - - if (!result.reflection.Valid()) - { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } - - EXPECT_EQ(result.reflection.NumInputParameters(), 4U); - { + EXPECT_EQ(result.reflection.NumInputParameters(), 1U); { const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "WORLDPOS"); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); EXPECT_EQ(inputParam->semanticIndex, 0U); EXPECT_EQ(inputParam->location, 0U); EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); - } - { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "NORMAL"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 1U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); - } - { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(2); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "TEXCOORD"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 2U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); - } - { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(3); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "LIGHTVECTORTS"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 3U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); } - } + EXPECT_EQ(result.reflection.InputParameter(1), nullptr); - EXPECT_EQ(result.reflection.NumOutputParameters(), 4U); - { + EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); { const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "WORLDPOS"); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); EXPECT_EQ(outputParam->semanticIndex, 0U); EXPECT_EQ(outputParam->location, 0U); EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); - } - { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "NORMAL"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 1U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); - } - { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(2); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "TEXCOORD"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 2U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); - } - { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(3); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "LIGHTVECTORTS"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 3U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); } - } + EXPECT_EQ(result.reflection.OutputParameter(1), nullptr); - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Patches_3_CtrlPoint); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); - EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::TriangleCW); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::FractionalOdd); + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 4U); - { - for (uint32_t i = 0; i < 3; ++i) - { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); - EXPECT_EQ(patchConstantParam->semanticIndex, i); - EXPECT_EQ(patchConstantParam->location, i); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); - } - { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(3); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); - EXPECT_EQ(patchConstantParam->semanticIndex, 0U); - EXPECT_EQ(patchConstantParam->location, 3U); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); - } - } - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); - EXPECT_EQ(result.reflection.NumResources(), 1U); - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbMain"); - EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); - - const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); - EXPECT_NE(cbuffer, nullptr); - EXPECT_STRCASEEQ(cbuffer->Name(), "cbMain"); - EXPECT_EQ(cbuffer->Size(), 16U); - - EXPECT_EQ(cbuffer->NumVariables(), 1U); + EXPECT_EQ(result.reflection.NumResources(), 1U); { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "tessellationFactor"); - EXPECT_STREQ(variable->type.Name(), "float4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 1U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 16U); + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbVS"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + EXPECT_EQ(result.reflection.ResourceByIndex(1), nullptr); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbVS"); + EXPECT_EQ(cbuffer->Size(), 64U); + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "wvp"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 64U); + } + EXPECT_EQ(result.reflection.ConstantBufferByIndex(1), nullptr); } } } - TEST(ReflectionTest, DomainShader) + TEST(ReflectionTest, HullShader) { - const std::string fileName = TEST_DATA_DIR "Input/PNTriangles_DS.hlsl"; + const std::string fileName = TEST_DATA_DIR "Input/DetailTessellation_HS.hlsl"; std::vector input = LoadFile(fileName, true); const std::string source = std::string(reinterpret_cast(input.data()), input.size()); @@ -313,170 +157,220 @@ namespace Compiler::Options options{}; options.needReflection = true; - const auto result = - Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::DomainShader}, options, {ShadingLanguage::Dxil, ""}); - - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); - - if (!result.reflection.Valid()) + for (const auto& testTarget : testTargets) { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::HullShader}, options, testTarget.target); - EXPECT_EQ(result.reflection.NumInputParameters(), 2U); - { - { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "POSITION"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 0U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); - } + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "TEXCOORD"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 1U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); } - } - EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); - { + EXPECT_EQ(result.reflection.NumInputParameters(), 4U); { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 0U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "WORLDPOS").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "NORMAL").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 1U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(2); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 2U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(3); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "LIGHTVECTORTS").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 3U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 4U); { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "TEXCOORD"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 1U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "WORLDPOS").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 0U); + } + else + { + EXPECT_EQ(outputParam->location, 3U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "NORMAL").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 1U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(2); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 2U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(3); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "LIGHTVECTORTS").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 3U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } } - } - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); - EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Patches_3_CtrlPoint); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::TriangleCW); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::FractionalOdd); - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 11U); - { - for (uint32_t i = 0; i < 3; ++i) - { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); - EXPECT_EQ(patchConstantParam->semanticIndex, i); - EXPECT_EQ(patchConstantParam->location, i); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); - } + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); + if (testTarget.target.language == ShadingLanguage::Dxil) { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(3); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); - EXPECT_EQ(patchConstantParam->semanticIndex, 0U); - EXPECT_EQ(patchConstantParam->location, 3U); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 4U); } - - const uint32_t locations[] = {0, 1, 2, 4, 5, 6}; - for (uint32_t i = 0; i < 6; ++i) + else { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i + 4); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "POSITION"); - EXPECT_EQ(patchConstantParam->semanticIndex, i + 3); - EXPECT_EQ(patchConstantParam->location, locations[i]); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, - Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 6U); } { - const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(10); - EXPECT_NE(patchConstantParam, nullptr); - EXPECT_STRCASEEQ(patchConstantParam->semantic, "CENTER"); - EXPECT_EQ(patchConstantParam->semanticIndex, 0U); - EXPECT_EQ(patchConstantParam->location, 7U); - EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(patchConstantParam->mask, - Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + uint32_t numTessFactors; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + numTessFactors = 3; + } + else + { + numTessFactors = 4; + } + for (uint32_t i = 0; i < numTessFactors; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, i); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, i); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = + result.reflection.HSDSPatchConstantParameter(numTessFactors); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 3U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); + } } - } - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); - EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); - EXPECT_EQ(result.reflection.NumResources(), 1U); - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbPNTriangles"); - EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); - - const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); - EXPECT_NE(cbuffer, nullptr); - EXPECT_STREQ(cbuffer->Name(), "cbPNTriangles"); - EXPECT_EQ(cbuffer->Size(), 80U); - - EXPECT_EQ(cbuffer->NumVariables(), 2U); + EXPECT_EQ(result.reflection.NumResources(), 1U); { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "viewProj"); - EXPECT_STREQ(variable->type.Name(), "float4x4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 4U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 64U); - } - { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "lightDir"); - EXPECT_STREQ(variable->type.Name(), "float4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 1U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 64U); - EXPECT_EQ(variable->size, 16U); + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbMain"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STRCASEEQ(cbuffer->Name(), "cbMain"); + EXPECT_EQ(cbuffer->Size(), 16U); + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "tessellationFactor"); + EXPECT_STREQ(variable->type.Name(), "float4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 16U); + } } } } - TEST(ReflectionTest, GeometryShader) + TEST(ReflectionTest, DomainShader) { - const std::string fileName = TEST_DATA_DIR "Input/Particle_GS.hlsl"; + const std::string fileName = TEST_DATA_DIR "Input/PNTriangles_DS.hlsl"; std::vector input = LoadFile(fileName, true); const std::string source = std::string(reinterpret_cast(input.data()), input.size()); @@ -484,118 +378,250 @@ namespace Compiler::Options options{}; options.needReflection = true; - std::vector defines = {{"FIXED_VERTEX_RADIUS", "5.0"}}; - const auto result = Compiler::Compile( - {source.c_str(), fileName.c_str(), "main", ShaderStage::GeometryShader, defines.data(), static_cast(defines.size())}, - options, {ShadingLanguage::Dxil, ""}); - - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); - - if (!result.reflection.Valid()) + for (const auto& testTarget : testTargets) { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::DomainShader}, options, testTarget.target); - EXPECT_EQ(result.reflection.NumInputParameters(), 1U); - { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "POSITION"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 0U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); - } + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); - EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); - { + if (!result.reflection.Valid()) { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 0U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); } + + EXPECT_EQ(result.reflection.NumInputParameters(), 2U); { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "TEXCOORD"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 1U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 0U); + } + else + { + EXPECT_EQ(inputParam->location, 1U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 1U); + } + else + { + EXPECT_EQ(inputParam->location, 8U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } } - } - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Points); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::TriangleStrip); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 4U); - EXPECT_EQ(result.reflection.GSNumInstances(), 1U); - - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); + { + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | + Reflection::ComponentMask::Z | Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 1U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + } - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); - EXPECT_EQ(result.reflection.NumResources(), 1U); - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbMain"); - EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); - - const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); - EXPECT_NE(cbuffer, nullptr); - EXPECT_STREQ(cbuffer->Name(), "cbMain"); - EXPECT_EQ(cbuffer->Size(), 128U); - - EXPECT_EQ(cbuffer->NumVariables(), 2U); + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); + if (testTarget.target.language == ShadingLanguage::Dxil) { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "invView"); - EXPECT_STREQ(variable->type.Name(), "float4x4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 4U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 64U); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 11U); } + else { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "viewProj"); - EXPECT_STREQ(variable->type.Name(), "float4x4"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 4U); - EXPECT_EQ(variable->type.Columns(), 4U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 64U); - EXPECT_EQ(variable->size, 64U); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 13U); + } + { + uint32_t numTessFactors; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + numTessFactors = 3; + } + else + { + numTessFactors = 4; + } + for (uint32_t i = 0; i < numTessFactors; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, i); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, i); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = + result.reflection.HSDSPatchConstantParameter(numTessFactors); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 3U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); + } + + uint32_t base; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + base = 4; + } + else + { + base = 6; + } + + const uint32_t dxilLocations[] = {0, 1, 2, 4, 5, 6}; + const uint32_t spirvLocations[] = {2, 3, 4, 5, 6, 7}; + for (uint32_t i = 0; i < 6; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(base + i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(patchConstantParam->semanticIndex, i + 3); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, dxilLocations[i]); + } + else + { + EXPECT_EQ(patchConstantParam->location, spirvLocations[i]); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(base + 6); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, (testTarget.inputParamPrefix + "CENTER").c_str()); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 7U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + } + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + EXPECT_EQ(result.reflection.NumResources(), 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbPNTriangles"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbPNTriangles"); + EXPECT_EQ(cbuffer->Size(), 80U); + + EXPECT_EQ(cbuffer->NumVariables(), 2U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "viewProj"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 64U); + } + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "lightDir"); + EXPECT_STREQ(variable->type.Name(), "float4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 64U); + EXPECT_EQ(variable->size, 16U); + } } } } - TEST(ReflectionTest, PixelShader) + TEST(ReflectionTest, GeometryShader) { - const std::string fileName = TEST_DATA_DIR "Input/ToneMapping_PS.hlsl"; + const std::string fileName = TEST_DATA_DIR "Input/Particle_GS.hlsl"; std::vector input = LoadFile(fileName, true); const std::string source = std::string(reinterpret_cast(input.data()), input.size()); @@ -603,74 +629,84 @@ namespace Compiler::Options options{}; options.needReflection = true; - const auto result = - Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::PixelShader}, options, {ShadingLanguage::Dxil, ""}); + for (const auto& testTarget : testTargets) + { + std::vector defines = {{"FIXED_VERTEX_RADIUS", "5.0"}}; + const auto result = Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::GeometryShader, defines.data(), + static_cast(defines.size())}, + options, testTarget.target); - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); - if (!result.reflection.Valid()) - { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } - EXPECT_EQ(result.reflection.NumInputParameters(), 2U); - { + EXPECT_EQ(result.reflection.NumInputParameters(), 1U); { const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "SV_Position"); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); EXPECT_EQ(inputParam->semanticIndex, 0U); EXPECT_EQ(inputParam->location, 0U); EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | Reflection::ComponentMask::W); } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); { - const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); - EXPECT_NE(inputParam, nullptr); - EXPECT_STRCASEEQ(inputParam->semantic, "TEXCOORD"); - EXPECT_EQ(inputParam->semanticIndex, 0U); - EXPECT_EQ(inputParam->location, 1U); - EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | + Reflection::ComponentMask::Z | Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 1U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } } - } - - EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); - { - const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); - EXPECT_NE(outputParam, nullptr); - EXPECT_STRCASEEQ(outputParam->semantic, "SV_Target"); - EXPECT_EQ(outputParam->semanticIndex, 0U); - EXPECT_EQ(outputParam->location, 0U); - EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); - EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | - Reflection::ComponentMask::W); - } - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); - EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Points); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::TriangleStrip); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 4U); + EXPECT_EQ(result.reflection.GSNumInstances(), 1U); - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); - EXPECT_EQ(result.reflection.NumResources(), 6U); - { + EXPECT_EQ(result.reflection.NumResources(), 1U); { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbPS"); + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbPS"); + EXPECT_STREQ(resource->name, "cbMain"); EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); EXPECT_EQ(resource->space, 0U); EXPECT_EQ(resource->bindPoint, 0U); @@ -678,70 +714,213 @@ namespace const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); EXPECT_NE(cbuffer, nullptr); - EXPECT_STREQ(cbuffer->Name(), "cbPS"); - EXPECT_EQ(cbuffer->Size(), 16U); + EXPECT_STREQ(cbuffer->Name(), "cbMain"); + EXPECT_EQ(cbuffer->Size(), 128U); - EXPECT_EQ(cbuffer->NumVariables(), 1U); + EXPECT_EQ(cbuffer->NumVariables(), 2U); { const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "lumStrength"); - EXPECT_STREQ(variable->type.Name(), "float"); + EXPECT_STREQ(variable->name, "invView"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 1U); - EXPECT_EQ(variable->type.Columns(), 1U); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); EXPECT_EQ(variable->type.Elements(), 0U); EXPECT_EQ(variable->type.ElementStride(), 0U); EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 4U); + EXPECT_EQ(variable->size, 64U); + } + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "viewProj"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 64U); + EXPECT_EQ(variable->size, 64U); } } + } + } + + TEST(ReflectionTest, PixelShader) + { + const std::string fileName = TEST_DATA_DIR "Input/ToneMapping_PS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::PixelShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("pointSampler"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "pointSampler"); - EXPECT_EQ(resource->type, ShaderResourceType::Sampler); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); } + + EXPECT_EQ(result.reflection.NumInputParameters(), 2U); { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("linearSampler"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "linearSampler"); - EXPECT_EQ(resource->type, ShaderResourceType::Sampler); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 1U); - EXPECT_EQ(resource->bindCount, 1U); + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, "SV_Position"); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 1U); + } + else + { + EXPECT_EQ(inputParam->location, 0U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("colorTex"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "colorTex"); - EXPECT_EQ(resource->type, ShaderResourceType::Texture); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "SV_Target").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); } + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + if (testTarget.target.language == ShadingLanguage::Dxil) { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("lumTex"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "lumTex"); - EXPECT_EQ(resource->type, ShaderResourceType::Texture); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 1U); - EXPECT_EQ(resource->bindCount, 1U); + EXPECT_EQ(result.reflection.NumResources(), 6U); } + else { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("bloomTex"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "bloomTex"); - EXPECT_EQ(resource->type, ShaderResourceType::Texture); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 2U); - EXPECT_EQ(resource->bindCount, 1U); + EXPECT_EQ(result.reflection.NumResources(), 9U); + } + { + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbPS"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbPS"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbPS"); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(cbuffer->Size(), 16U); + } + else + { + EXPECT_EQ(cbuffer->Size(), 4U); + } + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "lumStrength"); + EXPECT_STREQ(variable->type.Name(), "float"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 1U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 4U); + } + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("pointSampler"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "pointSampler"); + EXPECT_EQ(resource->type, ShaderResourceType::Sampler); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("linearSampler"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "linearSampler"); + EXPECT_EQ(resource->type, ShaderResourceType::Sampler); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 1U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("colorTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "colorTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("lumTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "lumTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 1U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("bloomTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "bloomTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 2U); + EXPECT_EQ(resource->bindCount, 1U); + } + EXPECT_EQ(result.reflection.ResourceByName("NotExists"), nullptr); } - EXPECT_EQ(result.reflection.ResourceByName("NotExists"), nullptr); } } @@ -755,147 +934,171 @@ namespace Compiler::Options options{}; options.needReflection = true; - const auto result = - Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::ComputeShader}, options, {ShadingLanguage::Dxil, ""}); - - EXPECT_FALSE(result.hasError); - EXPECT_FALSE(result.isText); - - if (!result.reflection.Valid()) + for (const auto& testTarget : testTargets) { - GTEST_SKIP_("Dxil Reflection is not supported on this platform"); - } + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::ComputeShader}, options, testTarget.target); - EXPECT_EQ(result.reflection.NumInputParameters(), 0U); - EXPECT_EQ(result.reflection.NumOutputParameters(), 0U); + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); - EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); - EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); - EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } - EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); - EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + EXPECT_EQ(result.reflection.NumInputParameters(), 0U); + EXPECT_EQ(result.reflection.NumOutputParameters(), 0U); - EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); - EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); - EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); - EXPECT_EQ(result.reflection.CSBlockSizeX(), 256U); - EXPECT_EQ(result.reflection.CSBlockSizeY(), 1U); - EXPECT_EQ(result.reflection.CSBlockSizeZ(), 1U); + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); - EXPECT_EQ(result.reflection.NumResources(), 4U); - { - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbSimulationConstants"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "cbSimulationConstants"); - EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); - const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); - EXPECT_NE(cbuffer, nullptr); - EXPECT_STREQ(cbuffer->Name(), "cbSimulationConstants"); - EXPECT_EQ(cbuffer->Size(), 112U); + EXPECT_EQ(result.reflection.CSBlockSizeX(), 256U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 1U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 1U); - EXPECT_EQ(cbuffer->NumVariables(), 2U); - { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "timeStep"); - EXPECT_STREQ(variable->type.Name(), "float"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(variable->type.Rows(), 1U); - EXPECT_EQ(variable->type.Columns(), 1U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->offset, 0U); - EXPECT_EQ(variable->size, 4U); - } + EXPECT_EQ(result.reflection.NumResources(), 4U); + { { - const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); - EXPECT_NE(variable, nullptr); - EXPECT_STREQ(variable->name, "scene"); - EXPECT_STREQ(variable->type.Name(), "Scene"); - EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Struct); - EXPECT_EQ(variable->type.Rows(), 1U); - EXPECT_EQ(variable->type.Columns(), 17U); - EXPECT_EQ(variable->type.Elements(), 0U); - EXPECT_EQ(variable->type.ElementStride(), 0U); - EXPECT_EQ(variable->type.NumMembers(), 3U); - EXPECT_EQ(variable->offset, 16U); - EXPECT_EQ(variable->size, 92U); - - { - const Reflection::VariableDesc* member = variable->type.MemberByIndex(0); - EXPECT_NE(member, nullptr); - EXPECT_STREQ(member->name, "wallStiffness"); - EXPECT_STREQ(member->type.Name(), "float"); - EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(member->type.Rows(), 1U); - EXPECT_EQ(member->type.Columns(), 1U); - EXPECT_EQ(member->type.Elements(), 0U); - EXPECT_EQ(member->type.ElementStride(), 0U); - EXPECT_EQ(member->offset, 0U); - EXPECT_EQ(member->size, 4U); - } + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbSimulationConstants"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbSimulationConstants"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbSimulationConstants"); + EXPECT_EQ(cbuffer->Size(), 112U); + + EXPECT_EQ(cbuffer->NumVariables(), 2U); { - const Reflection::VariableDesc* member = variable->type.MemberByIndex(1); - EXPECT_NE(member, nullptr); - EXPECT_STREQ(member->name, "gravity"); - EXPECT_STREQ(member->type.Name(), "float4"); - EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(member->type.Rows(), 1U); - EXPECT_EQ(member->type.Columns(), 4U); - EXPECT_EQ(member->type.Elements(), 0U); - EXPECT_EQ(member->type.ElementStride(), 0U); - EXPECT_EQ(member->offset, 16U); - EXPECT_EQ(member->size, 16U); + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "timeStep"); + EXPECT_STREQ(variable->type.Name(), "float"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 1U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 4U); } { - const Reflection::VariableDesc* member = variable->type.MemberByIndex(2); - EXPECT_NE(member, nullptr); - EXPECT_STREQ(member->name, "planes"); - EXPECT_STREQ(member->type.Name(), "float3"); - EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); - EXPECT_EQ(member->type.Rows(), 1U); - EXPECT_EQ(member->type.Columns(), 3U); - EXPECT_EQ(member->type.Elements(), 4U); - EXPECT_EQ(member->type.ElementStride(), 16U); - EXPECT_EQ(member->offset, 32U); - EXPECT_EQ(member->size, 60U); + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "scene"); + EXPECT_STREQ(variable->type.Name(), "Scene"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Struct); + EXPECT_EQ(variable->type.Rows(), 1U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(variable->type.Columns(), 17U); + } + else + { + EXPECT_EQ(variable->type.Columns(), 1U); + } + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->type.NumMembers(), 3U); + EXPECT_EQ(variable->offset, 16U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(variable->size, 92U); + } + else + { + EXPECT_EQ(variable->size, 96U); + } + + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(0); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "wallStiffness"); + EXPECT_STREQ(member->type.Name(), "float"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 1U); + EXPECT_EQ(member->type.Elements(), 0U); + EXPECT_EQ(member->type.ElementStride(), 0U); + EXPECT_EQ(member->offset, 0U); + EXPECT_EQ(member->size, 4U); + } + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(1); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "gravity"); + EXPECT_STREQ(member->type.Name(), "float4"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 4U); + EXPECT_EQ(member->type.Elements(), 0U); + EXPECT_EQ(member->type.ElementStride(), 0U); + EXPECT_EQ(member->offset, 16U); + EXPECT_EQ(member->size, 16U); + } + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(2); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "planes"); + EXPECT_STREQ(member->type.Name(), "float3"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 3U); + EXPECT_EQ(member->type.Elements(), 4U); + EXPECT_EQ(member->type.ElementStride(), 16U); + EXPECT_EQ(member->offset, 32U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(member->size, 60U); + } + else + { + EXPECT_EQ(member->size, 64U); + } + } } } - } - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRO"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "particlesRO"); - EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); - } - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesForcesRO"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "particlesForcesRO"); - EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 2U); - EXPECT_EQ(resource->bindCount, 1U); - } - { - const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRW"); - EXPECT_NE(resource, nullptr); - EXPECT_STREQ(resource->name, "particlesRW"); - EXPECT_EQ(resource->type, ShaderResourceType::UnorderedAccessView); - EXPECT_EQ(resource->space, 0U); - EXPECT_EQ(resource->bindPoint, 0U); - EXPECT_EQ(resource->bindCount, 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRO"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesRO"); + EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesForcesRO"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesForcesRO"); + EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 2U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRW"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesRW"); + EXPECT_EQ(resource->type, ShaderResourceType::UnorderedAccessView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } } } }