diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2020-12-04 13:03:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-04 10:03:29 -0800 |
| commit | 47ed0f68602a8ed0c425d2a4666969ad0db04ca6 (patch) | |
| tree | c104f182dbf1a2b9e12e8d383215749e11ab35dc /source/slang/slang-reflection-api.cpp | |
| parent | 277780ab7770453ed12e82df10d2a9d79ebf47dd (diff) | |
Projects in 'build' and Slang API separation (#1624)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Move reflection to reflection-api.
* Slight reorg to pull out potentially Slang internal functions from the reflection API impls.
* Remove visual studio projects
* Fix for slang-binaries copy.
* Add the visual studio projects in build/visual-studio
* Remove miniz project.
* Differentiate the linePath from the filePath.
* Improve comment in premake5.lua + to kick of CI.
* Kick CI.
Diffstat (limited to 'source/slang/slang-reflection-api.cpp')
| -rw-r--r-- | source/slang/slang-reflection-api.cpp | 2507 |
1 files changed, 2507 insertions, 0 deletions
diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp new file mode 100644 index 000000000..61990b7d0 --- /dev/null +++ b/source/slang/slang-reflection-api.cpp @@ -0,0 +1,2507 @@ +// slang-reflection-api.cpp + +#include "../core/slang-basic.h" +#include "slang-syntax.h" + +#include "../../slang.h" + +#include "slang-compiler.h" +#include "slang-type-layout.h" +#include "slang-syntax.h" +#include <assert.h> + +// Don't signal errors for stuff we don't implement here, +// and instead just try to return things defensively +// +// Slang developers can switch this when debugging. +#define SLANG_REFLECTION_UNEXPECTED() do {} while(0) + +namespace Slang +{ + +// Conversion routines to help with strongly-typed reflection API + +static inline UserDefinedAttribute* convert(SlangReflectionUserAttribute* attrib) +{ + return (UserDefinedAttribute*)attrib; +} +static inline SlangReflectionUserAttribute* convert(UserDefinedAttribute* attrib) +{ + return (SlangReflectionUserAttribute*)attrib; +} + +static inline Type* convert(SlangReflectionType* type) +{ + return (Type*) type; +} + +static inline SlangReflectionType* convert(Type* type) +{ + return (SlangReflectionType*) type; +} + +static inline TypeLayout* convert(SlangReflectionTypeLayout* type) +{ + return (TypeLayout*) type; +} + +static inline SlangReflectionTypeLayout* convert(TypeLayout* type) +{ + return (SlangReflectionTypeLayout*) type; +} + +static inline SpecializationParamLayout* convert(SlangReflectionTypeParameter * typeParam) +{ + return (SpecializationParamLayout*) typeParam; +} + +static inline VarDeclBase* convert(SlangReflectionVariable* var) +{ + return (VarDeclBase*) var; +} + +static inline SlangReflectionVariable* convert(VarDeclBase* var) +{ + return (SlangReflectionVariable*) var; +} + +static inline VarLayout* convert(SlangReflectionVariableLayout* var) +{ + return (VarLayout*) var; +} + +static inline SlangReflectionVariableLayout* convert(VarLayout* var) +{ + return (SlangReflectionVariableLayout*) var; +} + +static inline EntryPointLayout* convert(SlangReflectionEntryPoint* entryPoint) +{ + return (EntryPointLayout*) entryPoint; +} + +static inline SlangReflectionEntryPoint* convert(EntryPointLayout* entryPoint) +{ + return (SlangReflectionEntryPoint*) entryPoint; +} + +static inline ProgramLayout* convert(SlangReflection* program) +{ + return (ProgramLayout*) program; +} + +static inline SlangReflection* convert(ProgramLayout* program) +{ + return (SlangReflection*) program; +} + +// user attribute + +static unsigned int getUserAttributeCount(Decl* decl) +{ + unsigned int count = 0; + for (auto x : decl->getModifiersOfType<UserDefinedAttribute>()) + { + SLANG_UNUSED(x); + count++; + } + return count; +} + +static SlangReflectionUserAttribute* findUserAttributeByName(Session* session, Decl* decl, const char* name) +{ + auto nameObj = session->tryGetNameObj(name); + for (auto x : decl->getModifiersOfType<UserDefinedAttribute>()) + { + if (x->keywordName == nameObj) + return (SlangReflectionUserAttribute*)(x); + } + return nullptr; +} + +static SlangReflectionUserAttribute* getUserAttributeByIndex(Decl* decl, unsigned int index) +{ + unsigned int id = 0; + for (auto x : decl->getModifiersOfType<UserDefinedAttribute>()) + { + if (id == index) + return convert(x); + id++; + } + return nullptr; +} + + +// Attempt "do what I mean" remapping from the parameter category the user asked about, +// over to a parameter category that they might have meant. +static SlangParameterCategory maybeRemapParameterCategory( + TypeLayout* typeLayout, + SlangParameterCategory category) +{ + // Do we have an entry for the category they asked about? Then use that. + if (typeLayout->FindResourceInfo(LayoutResourceKind(category))) + return category; + + // Do we have an entry for the `DescriptorTableSlot` category? + if (typeLayout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot)) + { + // Is the category they were asking about one that makes sense for the type + // of this variable? + Type* type = typeLayout->getType(); + while (auto arrayType = as<ArrayExpressionType>(type)) + type = arrayType->baseType; + switch (spReflectionType_GetKind(convert(type))) + { + case SLANG_TYPE_KIND_CONSTANT_BUFFER: + if (category == SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + case SLANG_TYPE_KIND_RESOURCE: + if (category == SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + case SLANG_TYPE_KIND_SAMPLER_STATE: + if (category == SLANG_PARAMETER_CATEGORY_SAMPLER_STATE) + return SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT; + break; + + // TODO: implement more helpers here + + default: + break; + } + } + + return category; +} + +// Helpers for getting parameter count + +static unsigned getParameterCount(RefPtr<TypeLayout> typeLayout) +{ + if (auto parameterGroupLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + typeLayout = parameterGroupLayout->offsetElementTypeLayout; + } + + if (auto structLayout = as<StructTypeLayout>(typeLayout)) + { + return (unsigned)structLayout->fields.getCount(); + } + + return 0; +} + +static VarLayout* getParameterByIndex(RefPtr<TypeLayout> typeLayout, unsigned index) +{ + if (auto parameterGroupLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + typeLayout = parameterGroupLayout->offsetElementTypeLayout; + } + + if (auto structLayout = as<StructTypeLayout>(typeLayout)) + { + return structLayout->fields[index]; + } + + return 0; +} + +static SlangParameterCategory getParameterCategory( + LayoutResourceKind kind) +{ + return SlangParameterCategory(kind); +} + +static SlangParameterCategory getParameterCategory( + TypeLayout* typeLayout) +{ + auto resourceInfoCount = typeLayout->resourceInfos.getCount(); + if (resourceInfoCount == 1) + { + return getParameterCategory(typeLayout->resourceInfos[0].kind); + } + else if (resourceInfoCount == 0) + { + // TODO: can this ever happen? + return SLANG_PARAMETER_CATEGORY_NONE; + } + return SLANG_PARAMETER_CATEGORY_MIXED; +} + +static bool hasDefaultConstantBuffer(ScopeLayout* layout) +{ + auto typeLayout = layout->parametersLayout->getTypeLayout(); + return as<ParameterGroupTypeLayout>(typeLayout) != nullptr; +} + + +} // namespace Slang + +using namespace Slang; + +// Implementation to back public-facing reflection API + +SLANG_API char const* spReflectionUserAttribute_GetName(SlangReflectionUserAttribute* attrib) +{ + auto userAttr = convert(attrib); + if (!userAttr) return nullptr; + return userAttr->getKeywordName()->text.getBuffer(); +} +SLANG_API unsigned int spReflectionUserAttribute_GetArgumentCount(SlangReflectionUserAttribute* attrib) +{ + auto userAttr = convert(attrib); + if (!userAttr) return 0; + return (unsigned int)userAttr->args.getCount(); +} +SlangReflectionType* spReflectionUserAttribute_GetArgumentType(SlangReflectionUserAttribute* attrib, unsigned int index) +{ + auto userAttr = convert(attrib); + if (!userAttr) return nullptr; + return convert(userAttr->args[index]->type.type); +} +SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueInt(SlangReflectionUserAttribute* attrib, unsigned int index, int * rs) +{ + auto userAttr = convert(attrib); + if (!userAttr) return SLANG_ERROR_INVALID_PARAMETER; + if (index >= (unsigned int)userAttr->args.getCount()) return SLANG_ERROR_INVALID_PARAMETER; + NodeBase* val = nullptr; + if (userAttr->intArgVals.TryGetValue(index, val)) + { + *rs = (int)as<ConstantIntVal>(val)->value; + return 0; + } + return SLANG_ERROR_INVALID_PARAMETER; +} +SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueFloat(SlangReflectionUserAttribute* attrib, unsigned int index, float * rs) +{ + auto userAttr = convert(attrib); + if (!userAttr) return SLANG_ERROR_INVALID_PARAMETER; + if (index >= (unsigned int)userAttr->args.getCount()) return SLANG_ERROR_INVALID_PARAMETER; + if (auto cexpr = as<FloatingPointLiteralExpr>(userAttr->args[index])) + { + *rs = (float)cexpr->value; + return 0; + } + return SLANG_ERROR_INVALID_PARAMETER; +} +SLANG_API const char* spReflectionUserAttribute_GetArgumentValueString(SlangReflectionUserAttribute* attrib, unsigned int index, size_t* bufLen) +{ + auto userAttr = convert(attrib); + if (!userAttr) return nullptr; + if (index >= (unsigned int)userAttr->args.getCount()) return nullptr; + if (auto cexpr = as<StringLiteralExpr>(userAttr->args[index])) + { + if (bufLen) + *bufLen = cexpr->token.getContentLength(); + return cexpr->token.getContent().begin(); + } + return nullptr; +} + +// type Reflection + +SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return SLANG_TYPE_KIND_NONE; + + // TODO(tfoley: Don't emit the same type more than once... + + if (auto basicType = as<BasicExpressionType>(type)) + { + return SLANG_TYPE_KIND_SCALAR; + } + else if (auto vectorType = as<VectorExpressionType>(type)) + { + return SLANG_TYPE_KIND_VECTOR; + } + else if (auto matrixType = as<MatrixExpressionType>(type)) + { + return SLANG_TYPE_KIND_MATRIX; + } + else if (auto parameterBlockType = as<ParameterBlockType>(type)) + { + return SLANG_TYPE_KIND_PARAMETER_BLOCK; + } + else if (auto constantBufferType = as<ConstantBufferType>(type)) + { + return SLANG_TYPE_KIND_CONSTANT_BUFFER; + } + else if( auto streamOutputType = as<HLSLStreamOutputType>(type) ) + { + return SLANG_TYPE_KIND_OUTPUT_STREAM; + } + else if (as<TextureBufferType>(type)) + { + return SLANG_TYPE_KIND_TEXTURE_BUFFER; + } + else if (as<GLSLShaderStorageBufferType>(type)) + { + return SLANG_TYPE_KIND_SHADER_STORAGE_BUFFER; + } + else if (auto samplerStateType = as<SamplerStateType>(type)) + { + return SLANG_TYPE_KIND_SAMPLER_STATE; + } + else if (auto textureType = as<TextureTypeBase>(type)) + { + return SLANG_TYPE_KIND_RESOURCE; + } + else if (auto feedbackType = as<FeedbackType>(type)) + { + return SLANG_TYPE_KIND_FEEDBACK; + } + // TODO: need a better way to handle this stuff... +#define CASE(TYPE) \ + else if(as<TYPE>(type)) do { \ + return SLANG_TYPE_KIND_RESOURCE; \ + } while(0) + + CASE(HLSLStructuredBufferType); + CASE(HLSLRWStructuredBufferType); + CASE(HLSLRasterizerOrderedStructuredBufferType); + CASE(HLSLAppendStructuredBufferType); + CASE(HLSLConsumeStructuredBufferType); + CASE(HLSLByteAddressBufferType); + CASE(HLSLRWByteAddressBufferType); + CASE(HLSLRasterizerOrderedByteAddressBufferType); + CASE(UntypedBufferResourceType); +#undef CASE + + else if (auto arrayType = as<ArrayExpressionType>(type)) + { + return SLANG_TYPE_KIND_ARRAY; + } + else if( auto declRefType = as<DeclRefType>(type) ) + { + const auto& declRef = declRefType->declRef; + if(declRef.is<StructDecl>() ) + { + return SLANG_TYPE_KIND_STRUCT; + } + else if (declRef.is<GlobalGenericParamDecl>()) + { + return SLANG_TYPE_KIND_GENERIC_TYPE_PARAMETER; + } + else if (declRef.is<InterfaceDecl>()) + { + return SLANG_TYPE_KIND_INTERFACE; + } + else if (declRef.is<FuncDecl>()) + { + // This is a reference to an entry point + return SLANG_TYPE_KIND_STRUCT; + } + } + else if( auto specializedType = as<ExistentialSpecializedType>(type) ) + { + return SLANG_TYPE_KIND_SPECIALIZED; + } + else if (auto errorType = as<ErrorType>(type)) + { + // This means we saw a type we didn't understand in the user's code + return SLANG_TYPE_KIND_NONE; + } + + SLANG_REFLECTION_UNEXPECTED(); + return SLANG_TYPE_KIND_NONE; +} + +SLANG_API unsigned int spReflectionType_GetFieldCount(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + // TODO: maybe filter based on kind + + if(auto declRefType = as<DeclRefType>(type)) + { + auto declRef = declRefType->declRef; + if( auto structDeclRef = declRef.as<StructDecl>()) + { + return (unsigned int)getFields(structDeclRef, MemberFilterStyle::Instance).getCount(); + } + } + + return 0; +} + +SLANG_API SlangReflectionVariable* spReflectionType_GetFieldByIndex(SlangReflectionType* inType, unsigned index) +{ + auto type = convert(inType); + if(!type) return nullptr; + + // TODO: maybe filter based on kind + + if(auto declRefType = as<DeclRefType>(type)) + { + auto declRef = declRefType->declRef; + if( auto structDeclRef = declRef.as<StructDecl>()) + { + auto fields = getFields(structDeclRef, MemberFilterStyle::Instance); + auto fieldDeclRef = fields[index]; + return (SlangReflectionVariable*) fieldDeclRef.getDecl(); + } + } + + return nullptr; +} + +SLANG_API size_t spReflectionType_GetElementCount(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + if(auto arrayType = as<ArrayExpressionType>(type)) + { + return arrayType->arrayLength ? (size_t) getIntVal(arrayType->arrayLength) : 0; + } + else if( auto vectorType = as<VectorExpressionType>(type)) + { + return (size_t) getIntVal(vectorType->elementCount); + } + + return 0; +} + +SLANG_API SlangReflectionType* spReflectionType_GetElementType(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return nullptr; + + if(auto arrayType = as<ArrayExpressionType>(type)) + { + return (SlangReflectionType*) arrayType->baseType; + } + else if( auto parameterGroupType = as<ParameterGroupType>(type)) + { + return convert(parameterGroupType->elementType); + } + else if( auto vectorType = as<VectorExpressionType>(type)) + { + return convert(vectorType->elementType); + } + else if( auto matrixType = as<MatrixExpressionType>(type)) + { + return convert(matrixType->getElementType()); + } + + return nullptr; +} + +SLANG_API unsigned int spReflectionType_GetRowCount(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + if(auto matrixType = as<MatrixExpressionType>(type)) + { + return (unsigned int) getIntVal(matrixType->getRowCount()); + } + else if(auto vectorType = as<VectorExpressionType>(type)) + { + return 1; + } + else if( auto basicType = as<BasicExpressionType>(type) ) + { + return 1; + } + + return 0; +} + +SLANG_API unsigned int spReflectionType_GetColumnCount(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + if(auto matrixType = as<MatrixExpressionType>(type)) + { + return (unsigned int) getIntVal(matrixType->getColumnCount()); + } + else if(auto vectorType = as<VectorExpressionType>(type)) + { + return (unsigned int) getIntVal(vectorType->elementCount); + } + else if( auto basicType = as<BasicExpressionType>(type) ) + { + return 1; + } + + return 0; +} + +SLANG_API SlangScalarType spReflectionType_GetScalarType(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + if(auto matrixType = as<MatrixExpressionType>(type)) + { + type = matrixType->getElementType(); + } + else if(auto vectorType = as<VectorExpressionType>(type)) + { + type = vectorType->elementType; + } + + if(auto basicType = as<BasicExpressionType>(type)) + { + switch (basicType->baseType) + { +#define CASE(BASE, TAG) \ + case BaseType::BASE: return SLANG_SCALAR_TYPE_##TAG + + CASE(Void, VOID); + CASE(Bool, BOOL); + CASE(Int8, INT8); + CASE(Int16, INT16); + CASE(Int, INT32); + CASE(Int64, INT64); + CASE(UInt8, UINT8); + CASE(UInt16, UINT16); + CASE(UInt, UINT32); + CASE(UInt64, UINT64); + CASE(Half, FLOAT16); + CASE(Float, FLOAT32); + CASE(Double, FLOAT64); + +#undef CASE + + default: + SLANG_REFLECTION_UNEXPECTED(); + return SLANG_SCALAR_TYPE_NONE; + break; + } + } + + return SLANG_SCALAR_TYPE_NONE; +} + +SLANG_API unsigned int spReflectionType_GetUserAttributeCount(SlangReflectionType* inType) +{ + auto type = convert(inType); + if (!type) return 0; + if (auto declRefType = as<DeclRefType>(type)) + { + return getUserAttributeCount(declRefType->declRef.getDecl()); + } + return 0; +} +SLANG_API SlangReflectionUserAttribute* spReflectionType_GetUserAttribute(SlangReflectionType* inType, unsigned int index) +{ + auto type = convert(inType); + if (!type) return 0; + if (auto declRefType = as<DeclRefType>(type)) + { + return getUserAttributeByIndex(declRefType->declRef.getDecl(), index); + } + return 0; +} +SLANG_API SlangReflectionUserAttribute* spReflectionType_FindUserAttributeByName(SlangReflectionType* inType, char const* name) +{ + auto type = convert(inType); + if (!type) return 0; + if (auto declRefType = as<DeclRefType>(type)) + { + ASTBuilder* astBuilder = declRefType->getASTBuilder(); + auto globalSession = astBuilder->getGlobalSession(); + + return findUserAttributeByName(globalSession, declRefType->declRef.getDecl(), name); + } + return 0; +} + +SLANG_API SlangResourceShape spReflectionType_GetResourceShape(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + while(auto arrayType = as<ArrayExpressionType>(type)) + { + type = arrayType->baseType; + } + + if(auto textureType = as<TextureTypeBase>(type)) + { + return textureType->getShape(); + } + + // TODO: need a better way to handle this stuff... +#define CASE(TYPE, SHAPE, ACCESS) \ + else if(as<TYPE>(type)) do { \ + return SHAPE; \ + } while(0) + + CASE(HLSLStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ); + CASE(HLSLRWStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); + CASE(HLSLRasterizerOrderedStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_RASTER_ORDERED); + CASE(HLSLAppendStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_APPEND); + CASE(HLSLConsumeStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_CONSUME); + CASE(HLSLByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ); + CASE(HLSLRWByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); + CASE(HLSLRasterizerOrderedByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_RASTER_ORDERED); + CASE(RaytracingAccelerationStructureType, SLANG_ACCELERATION_STRUCTURE, SLANG_RESOURCE_ACCESS_READ); + CASE(UntypedBufferResourceType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ); +#undef CASE + + return SLANG_RESOURCE_NONE; +} + +SLANG_API SlangResourceAccess spReflectionType_GetResourceAccess(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return 0; + + while(auto arrayType = as<ArrayExpressionType>(type)) + { + type = arrayType->baseType; + } + + if(auto textureType = as<TextureTypeBase>(type)) + { + return textureType->getAccess(); + } + + // TODO: need a better way to handle this stuff... +#define CASE(TYPE, SHAPE, ACCESS) \ + else if(as<TYPE>(type)) do { \ + return ACCESS; \ + } while(0) + + CASE(HLSLStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ); + CASE(HLSLRWStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); + CASE(HLSLRasterizerOrderedStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_RASTER_ORDERED); + CASE(HLSLAppendStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_APPEND); + CASE(HLSLConsumeStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_CONSUME); + CASE(HLSLByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ); + CASE(HLSLRWByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); + CASE(HLSLRasterizerOrderedByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_RASTER_ORDERED); + CASE(UntypedBufferResourceType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ); + + // This isn't entirely accurate, but I can live with it for now + CASE(GLSLShaderStorageBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); +#undef CASE + + return SLANG_RESOURCE_ACCESS_NONE; +} + +SLANG_API char const* spReflectionType_GetName(SlangReflectionType* inType) +{ + auto type = convert(inType); + + if( auto declRefType = as<DeclRefType>(type) ) + { + auto declRef = declRefType->declRef; + + // Don't return a name for auto-generated anonymous types + // that represent `cbuffer` members, etc. + auto decl = declRef.getDecl(); + if(decl->hasModifier<ImplicitParameterGroupElementTypeModifier>()) + return nullptr; + + return getText(declRef.getName()).begin(); + } + + return nullptr; +} + +SLANG_API SlangReflectionType * spReflection_FindTypeByName(SlangReflection * reflection, char const * name) +{ + auto programLayout = convert(reflection); + auto program = programLayout->getProgram(); + + // TODO: We should extend this API to support getting error messages + // when type lookup fails. + // + Slang::DiagnosticSink sink( + programLayout->getTargetReq()->getLinkage()->getSourceManager()); + + try + { + Type* result = program->getTypeFromString(name, &sink); + return (SlangReflectionType*)result; + } + catch( ... ) + { + return nullptr; + } +} + +SLANG_API SlangReflectionTypeLayout* spReflection_GetTypeLayout( + SlangReflection* reflection, + SlangReflectionType* inType, + SlangLayoutRules /*rules*/) +{ + auto context = convert(reflection); + auto type = convert(inType); + auto targetReq = context->getTargetReq(); + + auto typeLayout = targetReq->getTypeLayout(type); + return convert(typeLayout); +} + +SLANG_API SlangReflectionType* spReflectionType_GetResourceResultType(SlangReflectionType* inType) +{ + auto type = convert(inType); + if(!type) return nullptr; + + while(auto arrayType = as<ArrayExpressionType>(type)) + { + type = arrayType->baseType; + } + + if (auto textureType = as<TextureTypeBase>(type)) + { + return convert(textureType->elementType); + } + + // TODO: need a better way to handle this stuff... +#define CASE(TYPE, SHAPE, ACCESS) \ + else if(as<TYPE>(type)) do { \ + return convert(as<TYPE>(type)->elementType); \ + } while(0) + + // TODO: structured buffer needs to expose type layout! + + CASE(HLSLStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ); + CASE(HLSLRWStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE); + CASE(HLSLRasterizerOrderedStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_RASTER_ORDERED); + CASE(HLSLAppendStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_APPEND); + CASE(HLSLConsumeStructuredBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_CONSUME); +#undef CASE + + return nullptr; +} + +// type Layout Reflection + +SLANG_API SlangReflectionType* spReflectionTypeLayout_GetType(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + return (SlangReflectionType*) typeLayout->type; +} + +SLANG_API SlangTypeKind spReflectionTypeLayout_getKind(SlangReflectionTypeLayout* inTypeLayout) +{ + if(!inTypeLayout) return SLANG_TYPE_KIND_NONE; + + if( auto type = spReflectionTypeLayout_GetType(inTypeLayout) ) + { + return spReflectionType_GetKind(type); + } + + auto typeLayout = convert(inTypeLayout); + if( as<StructTypeLayout>(typeLayout) ) + { + return SLANG_TYPE_KIND_STRUCT; + } + else if( as<ParameterGroupTypeLayout>(typeLayout) ) + { + return SLANG_TYPE_KIND_CONSTANT_BUFFER; + } + + return SLANG_TYPE_KIND_NONE; +} + +namespace +{ + static size_t getReflectionSize(LayoutSize size) + { + if(size.isFinite()) + return size.getFiniteValue(); + + return SLANG_UNBOUNDED_SIZE; + } +} + +SLANG_API size_t spReflectionTypeLayout_GetSize(SlangReflectionTypeLayout* inTypeLayout, SlangParameterCategory category) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto info = typeLayout->FindResourceInfo(LayoutResourceKind(category)); + if(!info) return 0; + + return getReflectionSize(info->count); +} + +SLANG_API int32_t spReflectionTypeLayout_getAlignment(SlangReflectionTypeLayout* inTypeLayout, SlangParameterCategory category) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + if( category == SLANG_PARAMETER_CATEGORY_UNIFORM ) + { + return int32_t(typeLayout->uniformAlignment); + } + else + { + return 1; + } +} + +SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetFieldByIndex(SlangReflectionTypeLayout* inTypeLayout, unsigned index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if(auto structTypeLayout = as<StructTypeLayout>(typeLayout)) + { + return (SlangReflectionVariableLayout*) structTypeLayout->fields[index].Ptr(); + } + + return nullptr; +} + +SLANG_API SlangInt spReflectionTypeLayout_findFieldIndexByName(SlangReflectionTypeLayout* inTypeLayout, const char* nameBegin, const char* nameEnd) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return -1; + + UnownedStringSlice name = nameEnd != nullptr ? UnownedStringSlice(nameBegin, nameEnd) : UnownedTerminatedStringSlice(nameBegin); + + if(auto structTypeLayout = as<StructTypeLayout>(typeLayout)) + { + Index fieldCount = structTypeLayout->fields.getCount(); + for(Index f = 0; f < fieldCount; ++f) + { + auto field = structTypeLayout->fields[f]; + if(getReflectionName(field->varDecl)->text.getUnownedSlice() == name) + return f; + } + } + + return -1; +} + +SLANG_API size_t spReflectionTypeLayout_GetElementStride(SlangReflectionTypeLayout* inTypeLayout, SlangParameterCategory category) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + if( auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout)) + { + switch (category) + { + // We store the stride explicitly for the uniform case + case SLANG_PARAMETER_CATEGORY_UNIFORM: + return arrayTypeLayout->uniformStride; + + // For most other cases (resource registers), the "stride" + // of an array is simply the number of resources (if any) + // consumed by its element type. + default: + { + auto elementTypeLayout = arrayTypeLayout->elementTypeLayout; + auto info = elementTypeLayout->FindResourceInfo(LayoutResourceKind(category)); + if(!info) return 0; + return getReflectionSize(info->count); + } + + // An important special case, though, is Vulkan descriptor-table slots, + // where an entire array will use a single `binding`, so that the + // effective stride is zero: + case SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT: + return 0; + } + } + + return 0; +} + +SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if( auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout)) + { + return (SlangReflectionTypeLayout*) arrayTypeLayout->elementTypeLayout.Ptr(); + } + else if( auto constantBufferTypeLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + return convert(constantBufferTypeLayout->offsetElementTypeLayout.Ptr()); + } + else if( auto structuredBufferTypeLayout = as<StructuredBufferTypeLayout>(typeLayout)) + { + return convert(structuredBufferTypeLayout->elementTypeLayout.Ptr()); + } + else if( auto specializedTypeLayout = as<ExistentialSpecializedTypeLayout>(typeLayout) ) + { + return convert(specializedTypeLayout->baseTypeLayout.Ptr()); + } + + return nullptr; +} + +SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetElementVarLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if( auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + return convert(parameterGroupTypeLayout->elementVarLayout.Ptr()); + } + + return nullptr; +} + +SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getContainerVarLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if( auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + return convert(parameterGroupTypeLayout->containerVarLayout.Ptr()); + } + + return nullptr; +} + +SLANG_API SlangParameterCategory spReflectionTypeLayout_GetParameterCategory(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return SLANG_PARAMETER_CATEGORY_NONE; + + return getParameterCategory(typeLayout); +} + +SLANG_API unsigned spReflectionTypeLayout_GetCategoryCount(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return (unsigned) typeLayout->resourceInfos.getCount(); +} + +SLANG_API SlangParameterCategory spReflectionTypeLayout_GetCategoryByIndex(SlangReflectionTypeLayout* inTypeLayout, unsigned index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return SLANG_PARAMETER_CATEGORY_NONE; + + return typeLayout->resourceInfos[index].kind; +} + +SLANG_API SlangMatrixLayoutMode spReflectionTypeLayout_GetMatrixLayoutMode(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return SLANG_MATRIX_LAYOUT_MODE_UNKNOWN; + + if( auto matrixLayout = as<MatrixTypeLayout>(typeLayout) ) + { + return matrixLayout->mode; + } + else + { + return SLANG_MATRIX_LAYOUT_MODE_UNKNOWN; + } + +} + +SLANG_API int spReflectionTypeLayout_getGenericParamIndex(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return -1; + + if(auto genericParamTypeLayout = as<GenericParamTypeLayout>(typeLayout)) + { + return (int) genericParamTypeLayout->paramIndex; + } + else + { + return -1; + } +} + +SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getPendingDataTypeLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + auto pendingDataTypeLayout = typeLayout->pendingDataTypeLayout.Ptr(); + return convert(pendingDataTypeLayout); +} + +SLANG_API SlangReflectionVariableLayout* spReflectionVariableLayout_getPendingDataLayout(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return nullptr; + + auto pendingDataLayout = varLayout->pendingVarLayout.Ptr(); + return convert(pendingDataLayout); +} + +SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return nullptr; + + if( auto specializedTypeLayout = as<ExistentialSpecializedTypeLayout>(typeLayout) ) + { + auto pendingDataVarLayout = specializedTypeLayout->pendingDataVarLayout.Ptr(); + return convert(pendingDataVarLayout); + } + else + { + return nullptr; + } +} + +namespace Slang +{ + struct BindingRangePathLink + { + BindingRangePathLink( + BindingRangePathLink* parent, + VarLayout* var) + : parent(parent) + , var(var) + {} + + BindingRangePathLink* parent; + VarLayout* var; + }; + + + Int _calcIndexOffset(BindingRangePathLink* path, LayoutResourceKind kind) + { + Int result = 0; + for( auto link = path; link; link = link->parent ) + { + if( auto resInfo = link->var->FindResourceInfo(kind) ) + { + result += resInfo->index; + } + } + return result; + } + + Int _calcSpaceOffset(BindingRangePathLink* path, LayoutResourceKind kind) + { + Int result = 0; + for( auto link = path; link; link = link->parent ) + { + if( auto resInfo = link->var->FindResourceInfo(kind) ) + { + result += resInfo->space; + } + } + return result; + } + + SlangBindingType _calcResourceBindingType( + Type* type) + { + if( auto resourceType = as<ResourceType>(type) ) + { + auto shape = resourceType->getBaseShape(); + + auto access = resourceType->getAccess(); + auto mutableFlag = access != SLANG_RESOURCE_ACCESS_READ ? SLANG_BINDING_TYPE_MUTABLE_FLAG : 0; + + switch( shape ) + { + default: + return SLANG_BINDING_TYPE_TEXTURE | mutableFlag; + + case SLANG_TEXTURE_BUFFER: + return SLANG_BINDING_TYPE_TYPED_BUFFER | mutableFlag; + } + + } + else if( auto structuredBufferType = as<HLSLStructuredBufferTypeBase>(type) ) + { + if( as<HLSLStructuredBufferType>(type) ) + { + return SLANG_BINDING_TYPE_RAW_BUFFER; + } + else + { + return SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER; + } + } + else if( as<RaytracingAccelerationStructureType>(type) ) + { + return SLANG_BINDING_TYPE_RAY_TRACTING_ACCELERATION_STRUCTURE; + } + else if( auto untypedBufferType = as<UntypedBufferResourceType>(type) ) + { + if( as<HLSLByteAddressBufferType>(type) ) + { + return SLANG_BINDING_TYPE_RAW_BUFFER; + } + else + { + return SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER; + } + } + else if( as<ConstantBufferType>(type) ) + { + return SLANG_BINDING_TYPE_CONSTANT_BUFFER; + } + else + { + SLANG_UNEXPECTED("unhandled resource binding type"); + } + } + + SlangBindingType _calcResourceBindingType( + TypeLayout* typeLayout) + { + if(auto type = typeLayout->getType()) + { + return _calcResourceBindingType(type); + } + + if(as<ParameterGroupTypeLayout>(typeLayout)) + { + return SLANG_BINDING_TYPE_CONSTANT_BUFFER; + } + else + { + SLANG_UNEXPECTED("unhandled resource binding type"); + } + } + + + SlangBindingType _calcBindingType( + Slang::TypeLayout* typeLayout, + LayoutResourceKind kind) + { + switch( kind ) + { + default: + return SLANG_BINDING_TYPE_UNKNOWN; + + // Some cases of `LayoutResourceKind` can be mapped + // directly to a `BindingType` because there is only + // one case of types that have that resource kind. + + #define CASE(FROM, TO) \ + case LayoutResourceKind::FROM: return SLANG_BINDING_TYPE_##TO + + CASE(ConstantBuffer, CONSTANT_BUFFER); + CASE(SamplerState, SAMPLER); + CASE(VaryingInput, VARYING_INPUT); + CASE(VaryingOutput, VARYING_OUTPUT); + CASE(ExistentialObjectParam, EXISTENTIAL_VALUE); + CASE(PushConstantBuffer, PUSH_CONSTANT); + // TODO: register space + + #undef CASE + + case LayoutResourceKind::ShaderResource: + case LayoutResourceKind::UnorderedAccess: + case LayoutResourceKind::DescriptorTableSlot: + return _calcResourceBindingType(typeLayout); + } + } + + static DeclRefType* asInterfaceType(Type* type) + { + if(auto declRefType = as<DeclRefType>(type)) + { + if(declRefType->declRef.as<InterfaceDecl>()) + { + return declRefType; + } + } + return nullptr; + } + + struct ExtendedTypeLayoutContext + { + TypeLayout* m_typeLayout; + TypeLayout::ExtendedInfo* m_extendedInfo; + + Dictionary<Int, Int> m_mapSpaceToDescriptorSetIndex; + + Int _findOrAddDescriptorSet(Int space) + { + Int index = 0; + if(m_mapSpaceToDescriptorSetIndex.TryGetValue(space, index)) + return index; + + index = m_extendedInfo->m_descriptorSets.getCount(); + m_mapSpaceToDescriptorSetIndex.Add(space, index); + + RefPtr<TypeLayout::ExtendedInfo::DescriptorSetInfo> descriptorSet = new TypeLayout::ExtendedInfo::DescriptorSetInfo(); + m_extendedInfo->m_descriptorSets.add(descriptorSet); + + return index; + } + + void addRangesRec(TypeLayout* typeLayout, BindingRangePathLink* path, LayoutSize multiplier) + { + if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) ) + { + // For a structure type, we need to recursively + // add the ranges for each field. + // + // Along the way we will make sure to properly update + // the offset information on the fields so that + // they properly show their binding-range offset + // within the parent type. + // + Index structBindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); + for( auto fieldVarLayout : structTypeLayout->fields ) + { + Index fieldBindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); + fieldVarLayout->bindingRangeOffset = fieldBindingRangeIndex - structBindingRangeIndex; + + auto fieldTypeLayout = fieldVarLayout->getTypeLayout(); + + + BindingRangePathLink fieldLink(path, fieldVarLayout); + addRangesRec(fieldTypeLayout, &fieldLink, multiplier); + } + return; + } + else if( auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout) ) + { + // For an array, we need to recursively add the + // element type of the array, but with an adjusted + // `multiplier` to account for the element count. + // + auto elementTypeLayout = arrayTypeLayout->elementTypeLayout; + LayoutSize elementCount = LayoutSize::infinite(); + if( auto arrayType = as<ArrayExpressionType>(arrayTypeLayout->type) ) + { + if( auto elementCountVal = arrayType->arrayLength ) + { + elementCount = LayoutSize::RawValue(getIntVal(elementCountVal)); + } + } + addRangesRec(elementTypeLayout, path, multiplier * elementCount); + return; + } + else if( auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout)) + { + // A parameter group (whether a `ConstantBuffer<>` or `ParameterBlock<>` + // introduces a separately-allocated "sub-object" in the application's + // layout for shader objects. + // + // We will represent the parameter group with a single sub-object + // binding range (and an associated sub-object range). + // + // We start out by looking at the resources consumed by the parameter group + // itself, to determine what kind of binding range to report it as. + // + Index bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); + SlangBindingType bindingType = SLANG_BINDING_TYPE_CONSTANT_BUFFER; + Index spaceOffset = -1; + LayoutResourceKind kind = LayoutResourceKind::None; + for(auto& resInfo : parameterGroupTypeLayout->resourceInfos) + { + kind = resInfo.kind; + switch(kind) + { + default: + continue; + + case LayoutResourceKind::ConstantBuffer: + case LayoutResourceKind::PushConstantBuffer: + case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::DescriptorTableSlot: + break; + } + + bindingType = _calcBindingType(typeLayout, kind); + spaceOffset = _calcSpaceOffset(path, kind); + break; + } + + TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; + bindingRange.leafTypeLayout = typeLayout; + bindingRange.bindingType = bindingType; + bindingRange.count = multiplier; + bindingRange.descriptorSetIndex = -1; + bindingRange.firstDescriptorRangeIndex = 0; + bindingRange.descriptorRangeCount = 0; + + if( kind == LayoutResourceKind::PushConstantBuffer ) + { + if(auto resInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform)) + { + bindingRange.count *= resInfo->count; + } + } + + // Every parameter group will introduce a sub-object range, + // which will include bindings based on the type of data + // inside the sub-object. + // + TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange; + subObjectRange.bindingRangeIndex = bindingRangeIndex; + + // It is possible that the sub-object has descriptor ranges + // that will need to be exposed upward, into the parent. + // + if( spaceOffset != -1 ) + { + Int descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset); + auto descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex]; + auto firstDescriptorRangeIndex = descriptorSet->descriptorRanges.getCount(); + + // TODO: We need to recursively add descriptor ranges (but not binding + // ranges!) for anything in the element type that "leaks" into + // the surrounding context. + // + switch(kind) + { + case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::Uniform: + case LayoutResourceKind::None: + break; + + default: + { + // This means we are in the constant-buffer-like case + // (even if the user wrote `ParameterBlock<T>`), and any + // resource usage inside the element type should "leak" + // out to the parent scope. + // + // It *also* means we should add a suitable descriptor + // range if one is required for the "container" type. + // + for(auto resInfo : parameterGroupTypeLayout->containerVarLayout->typeLayout->resourceInfos) + { + switch( resInfo.kind ) + { + case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::Uniform: + continue; + + default: + break; + } + + TypeLayout::ExtendedInfo::DescriptorRangeInfo descriptorRange; + descriptorRange.kind = resInfo.kind; + descriptorRange.bindingType = _calcBindingType(typeLayout, resInfo.kind); + descriptorRange.count = multiplier; + descriptorRange.indexOffset = _calcIndexOffset(path, resInfo.kind); + + if( resInfo.kind == LayoutResourceKind::PushConstantBuffer ) + { + if(auto uniformResInfo = parameterGroupTypeLayout->elementVarLayout->typeLayout->FindResourceInfo(LayoutResourceKind::Uniform)) + { + descriptorRange.count *= uniformResInfo->count; + } + } + + descriptorSet->descriptorRanges.add(descriptorRange); + } + + // Now we need to recursively walk the element type and add all its + // descriptor ranges, so that they can be used for binding in + // the parent. + // + // We have this a bit by collecting both binding ranges and + // descriptor ranges, and then throwing away the binding ranges + // from the element type. + // + BindingRangePathLink elementPath(path, parameterGroupTypeLayout->elementVarLayout); + + Index bindingRangeCountBefore = m_extendedInfo->m_bindingRanges.getCount(); + Index subObjectRangeCountBefore = m_extendedInfo->m_subObjectRanges.getCount(); + + addRangesRec(parameterGroupTypeLayout->elementVarLayout->typeLayout, &elementPath, multiplier); + + m_extendedInfo->m_bindingRanges.setCount(bindingRangeCountBefore); + m_extendedInfo->m_subObjectRanges.setCount(subObjectRangeCountBefore); + } + break; + } + + auto descriptorRangeCount = descriptorSet->descriptorRanges.getCount() - firstDescriptorRangeIndex; + bindingRange.descriptorSetIndex = descriptorSetIndex; + bindingRange.firstDescriptorRangeIndex = firstDescriptorRangeIndex; + bindingRange.descriptorRangeCount = descriptorRangeCount; + } + + m_extendedInfo->m_bindingRanges.add(bindingRange); + m_extendedInfo->m_subObjectRanges.add(subObjectRange); + return; + } + else if(asInterfaceType(typeLayout->type)) + { + // An `interface` type should introduce a sub-object range, + // with no concrete descriptor ranges to store its value + // (since we don't know until runtime what type of + // value will be plugged in). + // + + LayoutResourceKind kind = LayoutResourceKind::ExistentialObjectParam; + auto count = multiplier; + auto spaceOffset = _calcSpaceOffset(path, kind); + + Int descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset); + auto descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex]; + + TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; + bindingRange.leafTypeLayout = typeLayout; + bindingRange.bindingType = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE; + bindingRange.count = multiplier; + bindingRange.descriptorSetIndex = descriptorSetIndex; + bindingRange.firstDescriptorRangeIndex = descriptorSet->descriptorRanges.getCount(); + bindingRange.descriptorRangeCount = 1; + + TypeLayout::ExtendedInfo::SubObjectRangeInfo subObjectRange; + subObjectRange.bindingRangeIndex = m_extendedInfo->m_bindingRanges.getCount(); + + m_extendedInfo->m_bindingRanges.add(bindingRange); + m_extendedInfo->m_subObjectRanges.add(subObjectRange); + } + // TODO: We need to handle `interface` types here, because they are + // another case that introduces a "sub-object" for the purposes of + // application-side allocation. + // + // TODO: There are a few cases of "leaf" fields that might + // still result in multiple descriptors (or at least multiple + // `LayoutResourceKind`s) depending on the target. + // + // For eample, combined texture-sampler types should be treated + // as "leaf" fields for this code (since a portable engine would + // need to abstract over them), but would map to two descriptors + // on targets that don't actually support combining them. + else + { + Int resourceKindCount = typeLayout->resourceInfos.getCount(); + if(resourceKindCount == 0) + { + // This is a field that consumes no resources, and as + // such does not need a binding or descriptor ranges + // allocated for it. + // + return; + } + else if(resourceKindCount == 1) + { + auto& resInfo = typeLayout->resourceInfos[0]; + LayoutResourceKind kind = resInfo.kind; + + if(kind == LayoutResourceKind::Uniform) + { + // We do not consider uniform resource usage + // in the ranges we compute. + // + // TODO: We may need to revise that rule for types that + // represent resources, even when one or more targets + // map those resource types to ordinary/uniform data. + // + return; + } + + // This leaf field will map to a single binding range and, + // if it is appropriate, a single descriptor range. + // + auto bindingType = _calcBindingType(typeLayout, kind); + auto count = resInfo.count * multiplier; + auto indexOffset = _calcIndexOffset(path, kind); + auto spaceOffset = _calcSpaceOffset(path, kind); + + Int descriptorSetIndex = -1; + Int firstDescriptorIndex = 0; + RefPtr<TypeLayout::ExtendedInfo::DescriptorSetInfo> descriptorSet; + switch( kind ) + { + case LayoutResourceKind::RegisterSpace: + case LayoutResourceKind::VaryingInput: + case LayoutResourceKind::VaryingOutput: + case LayoutResourceKind::HitAttributes: + case LayoutResourceKind::RayPayload: + // Resource kinds that represent "varying" input/output + // do not manifest as entries in API descriptor tables. + // + // TODO: Neither do root constants, if we are being + // precise. This API really needs to carefully match + // the semantics of the target platform/API in terms + // of what things are descriptor-bound and which are + // not, so that a user can easily allocate the platform-specific + // descriptor sets using this info. + // + // (That said, we are purposefully *not* breaking apart + // samplers and SRV/UAV/CBV stuff for our D3D reflection + // of descriptor sets. It seems like the policy here + // really requires careful thought) + // + // TODO: Maybe the best answer is to leave decomposition + // of stuff into descriptor sets up to the application + // layer? This is especially true if a common case would + // be an application that doesn't support arbitrary manual + // binding of parameters to register/spaces. + // + break; + + default: + { + TypeLayout::ExtendedInfo::DescriptorRangeInfo descriptorRange; + descriptorRange.kind = kind; + descriptorRange.bindingType = bindingType; + descriptorRange.count = count; + descriptorRange.indexOffset = indexOffset; + + descriptorSetIndex = _findOrAddDescriptorSet(spaceOffset); + descriptorSet = m_extendedInfo->m_descriptorSets[descriptorSetIndex]; + + firstDescriptorIndex = descriptorSet->descriptorRanges.getCount(); + descriptorSet->descriptorRanges.add(descriptorRange); + } + break; + } + + + TypeLayout::ExtendedInfo::BindingRangeInfo bindingRange; + bindingRange.leafTypeLayout = typeLayout; + bindingRange.bindingType = _calcBindingType(typeLayout, kind); + bindingRange.count = count; + bindingRange.descriptorSetIndex = descriptorSetIndex; + bindingRange.firstDescriptorRangeIndex = firstDescriptorIndex; + bindingRange.descriptorRangeCount = 1; + + m_extendedInfo->m_bindingRanges.add(bindingRange); + } + else + { + // This type appears to be one that consumes multiple + // resource kinds, but was not handled by any of + // the special-case logic above. In such a case we + // are in trouble. + // + return; + } + } + } + }; + + TypeLayout::ExtendedInfo* getExtendedTypeLayout(TypeLayout* typeLayout) + { + if( !typeLayout->m_extendedInfo ) + { + RefPtr<TypeLayout::ExtendedInfo> extendedInfo = new TypeLayout::ExtendedInfo; + + ExtendedTypeLayoutContext context; + context.m_typeLayout = typeLayout; + context.m_extendedInfo = extendedInfo; + + context.addRangesRec(typeLayout, nullptr, 1); + + typeLayout->m_extendedInfo = extendedInfo; + } + return typeLayout->m_extendedInfo; + } +} + +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + return extTypeLayout->m_bindingRanges.getCount(); +} + +SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return SLANG_BINDING_TYPE_UNKNOWN; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if(index < 0) return 0; + if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + return bindingRange.bindingType; +} + +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if(index < 0) return 0; + if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + auto count = bindingRange.count; + return count.isFinite() ? SlangInt(count.getFiniteValue()) : -1; +} + +#if 0 +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return Slang::_findBindingRange(typeLayout, index).indexOffset; +} + +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return Slang::_findBindingRange(typeLayout, index).spaceOffset; +} +#endif + +SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if(index < 0) return 0; + if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + return convert(bindingRange.leafTypeLayout); +} + +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if(index < 0) return 0; + if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + return bindingRange.descriptorSetIndex; +} + +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + if(index < 0) return 0; + if(index >= extTypeLayout->m_bindingRanges.getCount()) return 0; + auto& bindingRange = extTypeLayout->m_bindingRanges[index]; + + return bindingRange.firstDescriptorRangeIndex; +} + +SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + return extTypeLayout->m_descriptorSets.getCount(); +} + +SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + return descriptorSet->spaceOffset; +} + +SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + return descriptorSet->descriptorRanges.getCount(); +} + +SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + if(rangeIndex < 0) return 0; + if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0; + auto& range = descriptorSet->descriptorRanges[rangeIndex]; + + return range.indexOffset; +} + +SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + if(rangeIndex < 0) return 0; + if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0; + auto& range = descriptorSet->descriptorRanges[rangeIndex]; + + auto count = range.count; + return count.isFinite() ? count.getFiniteValue() : -1; +} + +SLANG_API SlangBindingType spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + if(rangeIndex < 0) return 0; + if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0; + auto& range = descriptorSet->descriptorRanges[rangeIndex]; + + return range.bindingType; +} + +SLANG_API SlangParameterCategory spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(SlangReflectionTypeLayout* inTypeLayout, SlangInt setIndex, SlangInt rangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(setIndex < 0) return 0; + if(setIndex >= extTypeLayout->m_descriptorSets.getCount()) return 0; + auto descriptorSet = extTypeLayout->m_descriptorSets[setIndex]; + + if(rangeIndex < 0) return 0; + if(rangeIndex >= descriptorSet->descriptorRanges.getCount()) return 0; + auto& range = descriptorSet->descriptorRanges[rangeIndex]; + + return SlangParameterCategory(range.kind); +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + return extTypeLayout->m_subObjectRanges.getCount(); +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto extTypeLayout = Slang::getExtendedTypeLayout(typeLayout); + + if(subObjectRangeIndex < 0) return 0; + if(subObjectRangeIndex >= extTypeLayout->m_subObjectRanges.getCount()) return 0; + + return extTypeLayout->m_subObjectRanges[subObjectRangeIndex].bindingRangeIndex; +} + + +#if 0 +SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeSubObjectRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return Slang::_findBindingRange(typeLayout, index).subObjectRangeIndex; +} +#endif + + +SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt fieldIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) ) + { + getExtendedTypeLayout(structTypeLayout); + + return structTypeLayout->fields[fieldIndex]->bindingRangeOffset; + } + + return 0; +} + +#if 0 +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* inTypeLayout) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return Slang::_calcSubObjectRangeCount(typeLayout); +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeObjectCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto count = Slang::_findSubObjectRange(typeLayout, index).count; + return count.isFinite() ? SlangInt(count.getFiniteValue()) : -1; +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return Slang::_findSubObjectRange(typeLayout, index).bindingRangeIndex; +} + + +SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getSubObjectRangeTypeLayout(SlangReflectionTypeLayout* inTypeLayout, SlangInt index) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + return convert(Slang::_findSubObjectRange(typeLayout, index).leafTypeLayout); +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex); + return Slang::_getSubObjectDescriptorRangeCount(subObjectRange); +} + +SLANG_API SlangBindingType spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingType(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex); + return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).bindingType; +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingCount(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex); + auto count = Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).count; + return count.isFinite() ? count.getFiniteValue() : -1; +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeIndexOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex); + return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).indexOffset; +} + +SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeSpaceOffset(SlangReflectionTypeLayout* inTypeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject) +{ + auto typeLayout = convert(inTypeLayout); + if(!typeLayout) return 0; + + auto subObjectRange = Slang::_findSubObjectRange(typeLayout, subObjectRangeIndex); + return Slang::_getSubObjectDescriptorRange(subObjectRange, bindingRangeIndexInSubObject).spaceOffset; +} +#endif + +// Variable Reflection + +SLANG_API char const* spReflectionVariable_GetName(SlangReflectionVariable* inVar) +{ + auto var = convert(inVar); + if(!var) return nullptr; + + // If the variable is one that has an "external" name that is supposed + // to be exposed for reflection, then report it here + if(auto reflectionNameMod = var->findModifier<ParameterGroupReflectionName>()) + return getText(reflectionNameMod->nameAndLoc.name).getBuffer(); + + return getText(var->getName()).getBuffer(); +} + +SLANG_API SlangReflectionType* spReflectionVariable_GetType(SlangReflectionVariable* inVar) +{ + auto var = convert(inVar); + if(!var) return nullptr; + + return convert(var->getType()); +} + +SLANG_API SlangReflectionModifier* spReflectionVariable_FindModifier(SlangReflectionVariable* inVar, SlangModifierID modifierID) +{ + auto var = convert(inVar); + if(!var) return nullptr; + + Modifier* modifier = nullptr; + switch( modifierID ) + { + case SLANG_MODIFIER_SHARED: + modifier = var->findModifier<HLSLEffectSharedModifier>(); + break; + + default: + return nullptr; + } + + return (SlangReflectionModifier*) modifier; +} + +SLANG_API unsigned int spReflectionVariable_GetUserAttributeCount(SlangReflectionVariable* inVar) +{ + auto varDecl = convert(inVar); + if (!varDecl) return 0; + return getUserAttributeCount(varDecl); +} +SLANG_API SlangReflectionUserAttribute* spReflectionVariable_GetUserAttribute(SlangReflectionVariable* inVar, unsigned int index) +{ + auto varDecl = convert(inVar); + if (!varDecl) return 0; + return getUserAttributeByIndex(varDecl, index); +} +SLANG_API SlangReflectionUserAttribute* spReflectionVariable_FindUserAttributeByName(SlangReflectionVariable* inVar, SlangSession* session, char const* name) +{ + auto varDecl = convert(inVar); + if (!varDecl) return 0; + return findUserAttributeByName(asInternal(session), varDecl, name); +} + +// Variable Layout Reflection + +SLANG_API SlangReflectionVariable* spReflectionVariableLayout_GetVariable(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return nullptr; + + return convert(varLayout->varDecl.getDecl()); +} + +SLANG_API SlangReflectionTypeLayout* spReflectionVariableLayout_GetTypeLayout(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return nullptr; + + return convert(varLayout->getTypeLayout()); +} + +SLANG_API size_t spReflectionVariableLayout_GetOffset(SlangReflectionVariableLayout* inVarLayout, SlangParameterCategory category) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + auto info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + + if (!info) + { + // No match with requested category? Try again with one they might have meant... + category = maybeRemapParameterCategory(varLayout->getTypeLayout(), category); + info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + } + + if(!info) return 0; + + return info->index; +} + +SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayout* inVarLayout, SlangParameterCategory category) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + + auto info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + if (!info) + { + // No match with requested category? Try again with one they might have meant... + category = maybeRemapParameterCategory(varLayout->getTypeLayout(), category); + info = varLayout->FindResourceInfo(LayoutResourceKind(category)); + } + + UInt space = 0; + + // First, deal with any offset applied to the specific resource kind specified + if (info) + { + space += info->space; + } + + // Note: this code used to try and take a variable with + // an offset for `LayoutResourceKind::RegisterSpace` and + // add it to the space returned, but that isn't going + // to be right in some cases. + // + // Imageine if we have: + // + // struct X { Texture2D y; } + // struct S { Texture2D t; ParmaeterBlock<X> x; } + // + // Texture2D gA; + // S gS; + // + // We expect `gS` to have an offset for `LayoutResourceKind::ShaderResourceView` + // of one (since its texture must come after `gA`), and an offset for + // `LayoutResourceKind::RegisterSpace` of one (since the default space will be + // space zero). It would be incorrect for us to imply that `gS.t` should + // be `t1, space1`, though, because the space offset of `gS` doesn't actually + // apply to `t`. + // + // For now we are punting on this issue and leaving it in the hands of the + // application to determine when a space offset from an "outer" variable should + // apply to the locations of things in an "inner" variable. + // + // There is no policy we can apply locally in this function that + // will Just Work, so the best we can do is try to not lie. + + return space; +} + +SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + if (!(varLayout->flags & Slang::VarLayoutFlag::HasSemantic)) + return 0; + + return varLayout->semanticName.getBuffer(); +} + +SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return 0; + + if (!(varLayout->flags & Slang::VarLayoutFlag::HasSemantic)) + return 0; + + return varLayout->semanticIndex; +} + +SLANG_API SlangStage spReflectionVariableLayout_getStage( + SlangReflectionVariableLayout* inVarLayout) +{ + auto varLayout = convert(inVarLayout); + if(!varLayout) return SLANG_STAGE_NONE; + + // A parameter that is not a varying input or output is + // not considered to belong to a single stage. + // + // TODO: We might need to reconsider this for, e.g., entry + // point parameters, where they might be stage-specific even + // if they are uniform. + if (!varLayout->FindResourceInfo(Slang::LayoutResourceKind::VaryingInput) + && !varLayout->FindResourceInfo(Slang::LayoutResourceKind::VaryingOutput)) + { + return SLANG_STAGE_NONE; + } + + // TODO: We should find the stage for a variable layout by + // walking up the tree of layout information, until we find + // something that has a definitive stage attached to it (e.g., + // either an entry point or a GLSL translation unit). + // + // We don't currently have parent links in the reflection layout + // information, so doing that walk would be tricky right now, so + // it is easier to just bloat the representation and store yet another + // field on every variable layout. + return (SlangStage) varLayout->stage; +} + + +// Shader Parameter Reflection + +SLANG_API unsigned spReflectionParameter_GetBindingIndex(SlangReflectionParameter* inVarLayout) +{ + SlangReflectionVariableLayout* varLayout = (SlangReflectionVariableLayout*)inVarLayout; + return (unsigned) spReflectionVariableLayout_GetOffset( + varLayout, + spReflectionTypeLayout_GetParameterCategory( + spReflectionVariableLayout_GetTypeLayout(varLayout))); +} + +SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParameter* inVarLayout) +{ + SlangReflectionVariableLayout* varLayout = (SlangReflectionVariableLayout*)inVarLayout; + return (unsigned) spReflectionVariableLayout_GetSpace( + varLayout, + spReflectionTypeLayout_GetParameterCategory( + spReflectionVariableLayout_GetTypeLayout(varLayout))); +} + + + +// Entry Point Reflection + +SLANG_API char const* spReflectionEntryPoint_getName( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + return entryPointLayout ? getCstr(entryPointLayout->name) : nullptr; +} + +SLANG_API unsigned spReflectionEntryPoint_getParameterCount( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) return 0; + + return getParameterCount(entryPointLayout->parametersLayout->typeLayout); +} + +SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getParameterByIndex( + SlangReflectionEntryPoint* inEntryPoint, + unsigned index) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) return 0; + + return convert(getParameterByIndex(entryPointLayout->parametersLayout->typeLayout, index)); +} + +SLANG_API SlangStage spReflectionEntryPoint_getStage(SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + + if(!entryPointLayout) return SLANG_STAGE_NONE; + + return SlangStage(entryPointLayout->profile.getStage()); +} + +SLANG_API void spReflectionEntryPoint_getComputeThreadGroupSize( + SlangReflectionEntryPoint* inEntryPoint, + SlangUInt axisCount, + SlangUInt* outSizeAlongAxis) +{ + auto entryPointLayout = convert(inEntryPoint); + + if(!entryPointLayout) return; + if(!axisCount) return; + if(!outSizeAlongAxis) return; + + auto entryPointFunc = entryPointLayout->entryPoint; + if(!entryPointFunc) return; + + SlangUInt sizeAlongAxis[3] = { 1, 1, 1 }; + + // First look for the HLSL case, where we have an attribute attached to the entry point function + auto numThreadsAttribute = entryPointFunc.getDecl()->findModifier<NumThreadsAttribute>(); + if (numThreadsAttribute) + { + sizeAlongAxis[0] = numThreadsAttribute->x; + sizeAlongAxis[1] = numThreadsAttribute->y; + sizeAlongAxis[2] = numThreadsAttribute->z; + } + + // + + if(axisCount > 0) outSizeAlongAxis[0] = sizeAlongAxis[0]; + if(axisCount > 1) outSizeAlongAxis[1] = sizeAlongAxis[1]; + if(axisCount > 2) outSizeAlongAxis[2] = sizeAlongAxis[2]; + for( SlangUInt aa = 3; aa < axisCount; ++aa ) + { + outSizeAlongAxis[aa] = 1; + } +} + +SLANG_API int spReflectionEntryPoint_usesAnySampleRateInput( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) + return 0; + + if (entryPointLayout->profile.getStage() != Stage::Fragment) + return 0; + + return (entryPointLayout->flags & EntryPointLayout::Flag::usesAnySampleRateInput) != 0; +} + +SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getVarLayout( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) + return nullptr; + + return convert(entryPointLayout->parametersLayout); +} + +SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getResultVarLayout( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) + return nullptr; + + return convert(entryPointLayout->resultLayout); +} + +SLANG_API int spReflectionEntryPoint_hasDefaultConstantBuffer( + SlangReflectionEntryPoint* inEntryPoint) +{ + auto entryPointLayout = convert(inEntryPoint); + if(!entryPointLayout) + return 0; + + return hasDefaultConstantBuffer(entryPointLayout); +} + + +// SlangReflectionTypeParameter +SLANG_API char const* spReflectionTypeParameter_GetName(SlangReflectionTypeParameter * inTypeParam) +{ + auto specializationParam = convert(inTypeParam); + if( auto genericParamLayout = as<GenericSpecializationParamLayout>(specializationParam) ) + { + return genericParamLayout->decl->getName()->text.getBuffer(); + } + // TODO: Add case for existential type parameter? They don't have as simple of a notion of "name" as the generic case... + return nullptr; +} + +SLANG_API unsigned spReflectionTypeParameter_GetIndex(SlangReflectionTypeParameter * inTypeParam) +{ + auto typeParam = convert(inTypeParam); + return (unsigned)(typeParam->index); +} + +SLANG_API unsigned int spReflectionTypeParameter_GetConstraintCount(SlangReflectionTypeParameter* inTypeParam) +{ + auto specializationParam = convert(inTypeParam); + if(auto genericParamLayout = as<GenericSpecializationParamLayout>(specializationParam)) + { + if( auto globalGenericParamDecl = as<GlobalGenericParamDecl>(genericParamLayout->decl) ) + { + auto constraints = globalGenericParamDecl->getMembersOfType<GenericTypeConstraintDecl>(); + return (unsigned int)constraints.getCount(); + } + // TODO: Add case for entry-point generic parameters. + } + // TODO: Add case for existential type parameters. + return 0; +} + +SLANG_API SlangReflectionType* spReflectionTypeParameter_GetConstraintByIndex(SlangReflectionTypeParameter * inTypeParam, unsigned index) +{ + auto specializationParam = convert(inTypeParam); + if(auto genericParamLayout = as<GenericSpecializationParamLayout>(specializationParam)) + { + if( auto globalGenericParamDecl = as<GlobalGenericParamDecl>(genericParamLayout->decl) ) + { + auto constraints = globalGenericParamDecl->getMembersOfType<GenericTypeConstraintDecl>(); + return (SlangReflectionType*)constraints[index]->sup.Ptr(); + } + // TODO: Add case for entry-point generic parameters. + } + // TODO: Add case for existential type parameters. + return 0; +} + +// Shader Reflection + +SLANG_API unsigned spReflection_GetParameterCount(SlangReflection* inProgram) +{ + auto program = convert(inProgram); + if(!program) return 0; + + auto globalStructLayout = getGlobalStructLayout(program); + if (!globalStructLayout) + return 0; + + return (unsigned) globalStructLayout->fields.getCount(); +} + +SLANG_API SlangReflectionParameter* spReflection_GetParameterByIndex(SlangReflection* inProgram, unsigned index) +{ + auto program = convert(inProgram); + if(!program) return nullptr; + + auto globalStructLayout = getGlobalStructLayout(program); + if (!globalStructLayout) + return 0; + + return convert(globalStructLayout->fields[index].Ptr()); +} + +SLANG_API SlangReflectionVariableLayout* spReflection_getGlobalParamsVarLayout(SlangReflection* inProgram) +{ + auto program = convert(inProgram); + if(!program) return nullptr; + + return convert(program->parametersLayout); +} + +SLANG_API unsigned int spReflection_GetTypeParameterCount(SlangReflection * reflection) +{ + auto program = convert(reflection); + return (unsigned int) program->specializationParams.getCount(); +} + +SLANG_API SlangReflectionTypeParameter* spReflection_GetTypeParameterByIndex(SlangReflection * reflection, unsigned int index) +{ + auto program = convert(reflection); + return (SlangReflectionTypeParameter*) program->specializationParams[index].Ptr(); +} + +SLANG_API SlangReflectionTypeParameter * spReflection_FindTypeParameter(SlangReflection * inProgram, char const * name) +{ + auto program = convert(inProgram); + if (!program) return nullptr; + for( auto& param : program->specializationParams ) + { + auto genericParamLayout = as<GenericSpecializationParamLayout>(param); + if(!genericParamLayout) + continue; + + if(getText(genericParamLayout->decl->getName()) != UnownedTerminatedStringSlice(name)) + continue; + + return (SlangReflectionTypeParameter*) genericParamLayout; + } + + return 0; +} + +SLANG_API SlangUInt spReflection_getEntryPointCount(SlangReflection* inProgram) +{ + auto program = convert(inProgram); + if(!program) return 0; + + return SlangUInt(program->entryPoints.getCount()); +} + +SLANG_API SlangReflectionEntryPoint* spReflection_getEntryPointByIndex(SlangReflection* inProgram, SlangUInt index) +{ + auto program = convert(inProgram); + if(!program) return 0; + + return convert(program->entryPoints[(int) index].Ptr()); +} + +SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName(SlangReflection* inProgram, char const* name) +{ + auto program = convert(inProgram); + if(!program) return 0; + + // TODO: improve on naive linear search + for(auto ep : program->entryPoints) + { + if(ep->entryPoint.getName()->text == name) + { + return convert(ep); + } + } + + return nullptr; +} + +SLANG_API SlangUInt spReflection_getGlobalConstantBufferBinding(SlangReflection* inProgram) +{ + auto program = convert(inProgram); + if (!program) return 0; + auto cb = program->parametersLayout->FindResourceInfo(LayoutResourceKind::ConstantBuffer); + if (!cb) return 0; + return cb->index; +} + +SLANG_API size_t spReflection_getGlobalConstantBufferSize(SlangReflection* inProgram) +{ + auto program = convert(inProgram); + if (!program) return 0; + auto structLayout = getGlobalStructLayout(program); + auto uniform = structLayout->FindResourceInfo(LayoutResourceKind::Uniform); + if (!uniform) return 0; + return getReflectionSize(uniform->count); +} + +SLANG_API SlangReflectionType* spReflection_specializeType( + SlangReflection* inProgramLayout, + SlangReflectionType* inType, + SlangInt specializationArgCount, + SlangReflectionType* const* specializationArgs, + ISlangBlob** outDiagnostics) +{ + auto programLayout = convert(inProgramLayout); + if(!programLayout) return nullptr; + + auto unspecializedType = convert(inType); + if(!unspecializedType) return nullptr; + + auto linkage = programLayout->getProgram()->getLinkage(); + + DiagnosticSink sink(linkage->getSourceManager()); + + auto specializedType = linkage->specializeType(unspecializedType, specializationArgCount, (Type* const*) specializationArgs, &sink); + + sink.getBlobIfNeeded(outDiagnostics); + + return convert(specializedType); +} + +SLANG_API SlangUInt spReflection_getHashedStringCount( + SlangReflection* reflection) +{ + auto programLayout = convert(reflection); + auto slices = programLayout->hashedStringLiteralPool.getAdded(); + return slices.getCount(); +} + +SLANG_API const char* spReflection_getHashedString( + SlangReflection* reflection, + SlangUInt index, + size_t* outCount) +{ + auto programLayout = convert(reflection); + + auto slices = programLayout->hashedStringLiteralPool.getAdded(); + auto slice = slices[Index(index)]; + + *outCount = slice.getLength(); + return slice.begin(); +} + +SLANG_API int spComputeStringHash(const char* chars, size_t count) +{ + return (int)getStableHashCode32(chars, count); +} + +SLANG_API SlangReflectionTypeLayout* spReflection_getGlobalParamsTypeLayout( + SlangReflection* reflection) +{ + auto programLayout = convert(reflection); + if(!programLayout) return nullptr; + + return convert(programLayout->parametersLayout->typeLayout); +} |
