From d8969d87dcc9eea3f186a0c93c5e48d3d1659e05 Mon Sep 17 00:00:00 2001 From: Jay Kwak <82421531+jkwak-work@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:59:17 -0700 Subject: Replace stdlib with core-module on files and projects (#5411) This commit renames the files and projects to prefer "core-module" over "stdlib". The directory name `source/slang-stdlib` needs to be renamed too, and there will be another commit for it soon. --- source/slang-stdlib/CMakeLists.txt | 90 ++-- .../slang-embedded-core-module-source.cpp | 338 ++++++++++++++ source/slang-stdlib/slang-embedded-core-module.cpp | 26 ++ .../slang-stdlib/slang-embedded-stdlib-source.cpp | 338 -------------- source/slang-stdlib/slang-embedded-stdlib.cpp | 26 -- source/slang/CMakeLists.txt | 24 +- source/slang/slang-core-module-textures.cpp | 505 +++++++++++++++++++++ source/slang/slang-core-module-textures.h | 105 +++++ source/slang/slang-core-module.cpp | 25 + source/slang/slang-stdlib-textures.cpp | 505 --------------------- source/slang/slang-stdlib-textures.h | 105 ----- source/slang/slang-stdlib.cpp | 27 -- 12 files changed, 1056 insertions(+), 1058 deletions(-) create mode 100644 source/slang-stdlib/slang-embedded-core-module-source.cpp create mode 100644 source/slang-stdlib/slang-embedded-core-module.cpp delete mode 100644 source/slang-stdlib/slang-embedded-stdlib-source.cpp delete mode 100644 source/slang-stdlib/slang-embedded-stdlib.cpp create mode 100644 source/slang/slang-core-module-textures.cpp create mode 100644 source/slang/slang-core-module-textures.h create mode 100644 source/slang/slang-core-module.cpp delete mode 100644 source/slang/slang-stdlib-textures.cpp delete mode 100644 source/slang/slang-stdlib-textures.h delete mode 100644 source/slang/slang-stdlib.cpp (limited to 'source') diff --git a/source/slang-stdlib/CMakeLists.txt b/source/slang-stdlib/CMakeLists.txt index e7fed354a..fd9394e4a 100644 --- a/source/slang-stdlib/CMakeLists.txt +++ b/source/slang-stdlib/CMakeLists.txt @@ -1,7 +1,7 @@ # -# In this file, for stdlib source embed and stdlib embed itself, we define two +# In this file, for core module source embed and core module embed itself, we define two # targets, one which includes the embed and one which does not, these are -# linked in as needed to libslang and libslang-without-embedded-stdlib (for +# linked in as needed to libslang and libslang-without-embedded-core-module (for # slang-bootstrap) # # If MSVC supported weak linking we could just have a single library for each @@ -9,23 +9,23 @@ # # -# Generate an embeddable stdlib +# Generate an embeddable core module # -set(stdlib_generated_header_dir ${CMAKE_CURRENT_BINARY_DIR}) -set(stdlib_generated_header - ${stdlib_generated_header_dir}/slang-stdlib-generated.h +set(core_module_generated_header_dir ${CMAKE_CURRENT_BINARY_DIR}) +set(core_module_generated_header + ${core_module_generated_header_dir}/slang-core-module-generated.h ) add_custom_command( - OUTPUT ${stdlib_generated_header} + OUTPUT ${core_module_generated_header} COMMAND slang-bootstrap -archive-type riff-lz4 -save-core-module-bin-source - ${stdlib_generated_header} + ${core_module_generated_header} DEPENDS slang-bootstrap VERBATIM ) -set(stdlib_common_args +set(core_module_common_args . OBJECT EXCLUDE_FROM_ALL @@ -34,20 +34,20 @@ set(stdlib_common_args FOLDER generated LINK_WITH_PRIVATE core USE_EXTRA_WARNINGS - EXPLICIT_SOURCE ./slang-embedded-stdlib.cpp + EXPLICIT_SOURCE ./slang-embedded-core-module.cpp ) slang_add_target( - ${stdlib_common_args} - TARGET_NAME slang-embedded-stdlib - EXPLICIT_SOURCE ${stdlib_generated_header} - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_STDLIB - INCLUDE_DIRECTORIES_PRIVATE ${stdlib_generated_header_dir} + ${core_module_common_args} + TARGET_NAME slang-embedded-core-module + EXPLICIT_SOURCE ${core_module_generated_header} + EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_CORE_MODULE + INCLUDE_DIRECTORIES_PRIVATE ${core_module_generated_header_dir} ) slang_add_target( - ${stdlib_common_args} - TARGET_NAME slang-no-embedded-stdlib + ${core_module_common_args} + TARGET_NAME slang-no-embedded-core-module ) # @@ -55,46 +55,46 @@ slang_add_target( # # List of *.meta.slang headers -set(stdlib_meta_source_dir "${slang_SOURCE_DIR}/source/slang") -glob_append(stdlib_meta_source "${stdlib_meta_source_dir}/*.meta.slang") +set(core_module_meta_source_dir "${slang_SOURCE_DIR}/source/slang") +glob_append(core_module_meta_source "${core_module_meta_source_dir}/*.meta.slang") -set(stdlib_meta_output_dir "${CMAKE_CURRENT_BINARY_DIR}/stdlib-meta") +set(core_module_meta_output_dir "${CMAKE_CURRENT_BINARY_DIR}/core-module-meta") # Generate the output file list -set(stdlib_meta_generated_headers) -foreach(meta_source ${stdlib_meta_source}) +set(core_module_meta_generated_headers) +foreach(meta_source ${core_module_meta_source}) file( RELATIVE_PATH meta_source_relative - "${stdlib_meta_source_dir}" + "${core_module_meta_source_dir}" ${meta_source} ) list( APPEND - stdlib_meta_generated_headers - "${stdlib_meta_output_dir}/${meta_source_relative}.h" + core_module_meta_generated_headers + "${core_module_meta_output_dir}/${meta_source_relative}.h" ) endforeach() add_custom_command( - OUTPUT ${stdlib_meta_generated_headers} - COMMAND ${CMAKE_COMMAND} -E make_directory ${stdlib_meta_output_dir} + OUTPUT ${core_module_meta_generated_headers} + COMMAND ${CMAKE_COMMAND} -E make_directory ${core_module_meta_output_dir} COMMAND - slang-generate ${stdlib_meta_source} --target-directory - ${stdlib_meta_output_dir} - DEPENDS ${stdlib_meta_source} slang-generate - WORKING_DIRECTORY "${stdlib_meta_source_dir}" + slang-generate ${core_module_meta_source} --target-directory + ${core_module_meta_output_dir} + DEPENDS ${core_module_meta_source} slang-generate + WORKING_DIRECTORY "${core_module_meta_source_dir}" VERBATIM ) -add_custom_target(generate-stdlib-headers DEPENDS ${stdlib_meta_generated_headers}) -set_target_properties(generate-stdlib-headers PROPERTIES FOLDER generated) +add_custom_target(generate-core-module-headers DEPENDS ${core_module_meta_generated_headers}) +set_target_properties(generate-core-module-headers PROPERTIES FOLDER generated) # -# Generate embedded stdlib source +# Generate embedded core module source # -set(stdlib_source_common_args +set(core_module_source_common_args . OBJECT EXCLUDE_FROM_ALL @@ -107,23 +107,23 @@ set(stdlib_source_common_args INCLUDE_DIRECTORIES_PRIVATE ../slang FOLDER generated EXPLICIT_SOURCE - ./slang-embedded-stdlib-source.cpp - ${stdlib_meta_generated_headers} - REQUIRES generate-stdlib-headers - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_STDLIB_SOURCE + ./slang-embedded-core-module-source.cpp + ${core_module_meta_generated_headers} + REQUIRES generate-core-module-headers + EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_CORE_MODULE_SOURCE INCLUDE_DIRECTORIES_PRIVATE - ${stdlib_meta_output_dir} + ${core_module_meta_output_dir} EXPORT_MACRO_PREFIX SLANG EXPORT_TYPE_AS ${SLANG_LIB_TYPE} ) slang_add_target( - ${stdlib_source_common_args} - TARGET_NAME slang-embedded-stdlib-source - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_STDLIB_SOURCE + ${core_module_source_common_args} + TARGET_NAME slang-embedded-core-module-source + EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_EMBED_CORE_MODULE_SOURCE ) slang_add_target( - ${stdlib_source_common_args} - TARGET_NAME slang-no-embedded-stdlib-source + ${core_module_source_common_args} + TARGET_NAME slang-no-embedded-core-module-source ) diff --git a/source/slang-stdlib/slang-embedded-core-module-source.cpp b/source/slang-stdlib/slang-embedded-core-module-source.cpp new file mode 100644 index 000000000..f8ea00045 --- /dev/null +++ b/source/slang-stdlib/slang-embedded-core-module-source.cpp @@ -0,0 +1,338 @@ +#include "slang-compiler.h" +#include "slang-ir.h" +#include "slang-ir-util.h" +#include "slang-core-module-textures.h" + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define LINE_STRING STRINGIZE(__LINE__) + +namespace Slang +{ + // We are going to generate the core module source code from a more compact + // description. For example, we need to generate all the `operator` + // declarations for the basic unary and binary math operations on + // builtin types. To do this, we will make a big array of all these + // types, and associate them with data on their categories/capabilities + // so that we generate only the correct operations. + // + enum + { + SINT_MASK = 1 << 0, + FLOAT_MASK = 1 << 1, + BOOL_RESULT = 1 << 2, + BOOL_MASK = 1 << 3, + UINT_MASK = 1 << 4, + + INT_MASK = SINT_MASK | UINT_MASK, + ARITHMETIC_MASK = INT_MASK | FLOAT_MASK, + LOGICAL_MASK = INT_MASK | BOOL_MASK, + ANY_MASK = INT_MASK | FLOAT_MASK | BOOL_MASK, + }; + + // We are going to declare initializers that allow for conversion between + // all of our base types, and we need a way to priotize those conversion + // by giving them different costs. Rather than maintain a hard-coded table + // of N^2 costs for N basic types, we are going to try to do things a bit + // more systematically. + // + // Every base type will be given a "kind" and a "rank" for conversion. + // The kind will classify it as signed/unsigned/float, and the rank will + // classify it by its logical bit size (with a distinct rank for pointer-sized + // types that logically sits between 32- and 64-bit types). + // + enum BaseTypeConversionKind : uint8_t + { + kBaseTypeConversionKind_Signed, + kBaseTypeConversionKind_Unsigned, + kBaseTypeConversionKind_Float, + kBaseTypeConversionKind_Error, + }; + enum BaseTypeConversionRank : uint8_t + { + kBaseTypeConversionRank_Bool, + kBaseTypeConversionRank_Int8, + kBaseTypeConversionRank_Int16, + kBaseTypeConversionRank_Int32, + kBaseTypeConversionRank_IntPtr, + kBaseTypeConversionRank_Int64, + kBaseTypeConversionRank_Error, + }; + + // Here we declare the table of all our builtin types, so that we can generate all the relevant declarations. + // + struct BaseTypeConversionInfo + { + char const* name; + BaseType tag; + unsigned flags; + BaseTypeConversionKind conversionKind; + BaseTypeConversionRank conversionRank; + }; + static const BaseTypeConversionInfo kBaseTypes[] = { + // TODO: `void` really shouldn't be in the `BaseType` enumeration, since it behaves so differently across the board + { "void", BaseType::Void, 0, kBaseTypeConversionKind_Error, kBaseTypeConversionRank_Error}, + + { "bool", BaseType::Bool, BOOL_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Bool }, + + { "int8_t", BaseType::Int8, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int8}, + { "int16_t", BaseType::Int16, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int16}, + { "int", BaseType::Int, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int32}, + { "int64_t", BaseType::Int64, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int64}, + { "intptr_t", BaseType::IntPtr, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_IntPtr}, + + + { "half", BaseType::Half, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int16}, + { "float", BaseType::Float, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int32}, + { "double", BaseType::Double, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int64}, + + { "uint8_t", BaseType::UInt8, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int8}, + { "uint16_t", BaseType::UInt16, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int16}, + { "uint", BaseType::UInt, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int32}, + { "uint64_t", BaseType::UInt64, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int64}, + { "uintptr_t", BaseType::UIntPtr, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_IntPtr}, + + }; + + void Session::finalizeSharedASTBuilder() + { + // Force creation of all builtin types so we can make sure + // they are created by the builtin AST builder instead of + // some user linkage's ast builder. This avoid the problem + // of storing a reference to these global types that are + // owned by a user linkage that gets deleted with the linkage. + // + globalAstBuilder->getNoneType(); + globalAstBuilder->getNullPtrType(); + globalAstBuilder->getBottomType(); + globalAstBuilder->getErrorType(); + globalAstBuilder->getInitializerListType(); + globalAstBuilder->getOverloadedType(); + globalAstBuilder->getStringType(); + globalAstBuilder->getEnumTypeType(); + globalAstBuilder->getDiffInterfaceType(); + globalAstBuilder->getSharedASTBuilder()->getDynamicType(); + globalAstBuilder->getSharedASTBuilder()->getDiffInterfaceType(); + globalAstBuilder->getSharedASTBuilder()->getNativeStringType(); + for (auto& baseType : kBaseTypes) + globalAstBuilder->getBuiltinType(baseType.tag); + } + + + // Given two base types, we need to be able to compute the cost of converting between them. + ConversionCost getBaseTypeConversionCost( + BaseTypeConversionInfo const& toInfo, + BaseTypeConversionInfo const& fromInfo) + { + if(toInfo.conversionKind == fromInfo.conversionKind + && toInfo.conversionRank == fromInfo.conversionRank) + { + // Thse should represent the exact same type. + return kConversionCost_None; + } + + // Conversions within the same kind are easist to handle + if (toInfo.conversionKind == fromInfo.conversionKind) + { + // If we are converting to a "larger" type, then + // we are doing a lossless promotion, and otherwise + // we are doing a demotion. + if (toInfo.conversionRank > fromInfo.conversionRank) + return kConversionCost_RankPromotion; + else + return kConversionCost_GeneralConversion; + } + else if (fromInfo.tag == BaseType::Bool && toInfo.tag == BaseType::Int) + { + return kConversionCost_BoolToInt; + } + + // If we are converting from an unsigned integer type to + // a signed integer type that is guaranteed to be larger, + // then that is also a lossless promotion. + // + // There is one additional wrinkle here, which is that + // a conversion from a 32-bit unsigned integer to a + // "pointer-sized" signed integer should be treated + // as unsafe, because the pointer size might also be + // 32 bits. + // + // The same basic exemption applied when converting + // *from* a pointer-sized unsigned integer. + else if(toInfo.conversionKind == kBaseTypeConversionKind_Signed + && fromInfo.conversionKind == kBaseTypeConversionKind_Unsigned + && toInfo.conversionRank > fromInfo.conversionRank + && toInfo.conversionRank != kBaseTypeConversionRank_IntPtr + && fromInfo.conversionRank != kBaseTypeConversionRank_IntPtr) + { + return kConversionCost_UnsignedToSignedPromotion; + } + // Same-size unsigned to signed integer conversion. + else if (toInfo.conversionKind == kBaseTypeConversionKind_Signed + && fromInfo.conversionKind == kBaseTypeConversionKind_Unsigned + && toInfo.conversionRank == fromInfo.conversionRank + && toInfo.conversionRank != kBaseTypeConversionRank_IntPtr + && fromInfo.conversionRank != kBaseTypeConversionRank_IntPtr) + { + return kConversionCost_SameSizeUnsignedToSignedConversion; + } + + // Conversion from signed to unsigned is always lossy, + // but it is preferred over conversions from unsigned + // to signed, for same-size types. + else if(toInfo.conversionKind == kBaseTypeConversionKind_Unsigned + && fromInfo.conversionKind == kBaseTypeConversionKind_Signed + && toInfo.conversionRank >= fromInfo.conversionRank) + { + return kConversionCost_SignedToUnsignedConversion; + } + + // Conversion from an integer to a floating-point type + // is never considered a promotion (even when the value + // would fit in the available mantissa bits). + // If the destination type is at least 32 bits we consider + // this a reasonably good conversion, though. + // + // Note that this means we do *not* consider implicit + // conversion to `half` as a good conversion, even for small + // types. This makes sense because we relaly want to prefer + // conversion to `float` as the default. + else if (toInfo.conversionKind == kBaseTypeConversionKind_Float + && toInfo.conversionRank >= kBaseTypeConversionRank_Int32 + && fromInfo.conversionRank >= kBaseTypeConversionRank_Int8) + { + return kConversionCost_IntegerToFloatConversion; + } + else if (toInfo.conversionKind == kBaseTypeConversionKind_Float + && toInfo.conversionRank >= kBaseTypeConversionRank_Int16 + && fromInfo.conversionRank >= kBaseTypeConversionRank_Int8) + { + return kConversionCost_IntegerToHalfConversion; + } + // All other cases are considered as "general" conversions, + // where we don't consider any one conversion better than + // any others. + else + { + return kConversionCost_GeneralConversion; + } + } + + IROp getBaseTypeConversionOp( + BaseTypeConversionInfo const& toInfo, + BaseTypeConversionInfo const& fromInfo) + { + if (toInfo.tag == fromInfo.tag) + return kIROp_Nop; + + IROp intrinsicOpCode = kIROp_Nop; + auto toStyle = getTypeStyle(toInfo.tag); + auto fromStyle = getTypeStyle(fromInfo.tag); + if (toStyle == kIROp_BoolType) toStyle = kIROp_IntType; + if (fromStyle == kIROp_BoolType) fromStyle = kIROp_IntType; + if (toStyle == kIROp_IntType && fromStyle == kIROp_IntType) + intrinsicOpCode = kIROp_IntCast; + if (toStyle == kIROp_IntType && fromStyle == kIROp_FloatType) + intrinsicOpCode = kIROp_CastFloatToInt; + if (toStyle == kIROp_FloatType && fromStyle == kIROp_IntType) + intrinsicOpCode = kIROp_CastIntToFloat; + if (toStyle == kIROp_FloatType && fromStyle == kIROp_FloatType) + intrinsicOpCode = kIROp_FloatCast; + return intrinsicOpCode; + } + + struct IntrinsicOpInfo { IROp opCode; char const* funcName; char const* opName; char const* interface; unsigned flags; }; + + [[maybe_unused]] + static const IntrinsicOpInfo intrinsicUnaryOps[] = { + { kIROp_Neg, "neg", "-", "__BuiltinArithmeticType", ARITHMETIC_MASK }, + { kIROp_Not, "logicalNot", "!", nullptr, BOOL_MASK | BOOL_RESULT }, + { kIROp_BitNot, "not", "~", "__BuiltinLogicalType", INT_MASK }, + }; + + [[maybe_unused]] + static const IntrinsicOpInfo intrinsicBinaryOps[] = { + {kIROp_Add, "add", "+", "__BuiltinArithmeticType", ARITHMETIC_MASK}, + {kIROp_Sub, "sub", "-", "__BuiltinArithmeticType", ARITHMETIC_MASK}, + {kIROp_Mul, "mul", "*", "__BuiltinArithmeticType", ARITHMETIC_MASK}, + {kIROp_Div, "div", "/", "__BuiltinArithmeticType", ARITHMETIC_MASK}, + {kIROp_IRem, "irem", "%", "__BuiltinIntegerType", INT_MASK}, + {kIROp_FRem, "frem", "%", "__BuiltinFloatingPointType", FLOAT_MASK}, + {kIROp_And, "logicalAnd", "&&", nullptr, BOOL_MASK | BOOL_RESULT}, + {kIROp_Or, "logicalOr", "||", nullptr, BOOL_MASK | BOOL_RESULT}, + {kIROp_BitAnd, "and", "&", "__BuiltinLogicalType", LOGICAL_MASK}, + {kIROp_BitOr, "or", "|", "__BuiltinLogicalType", LOGICAL_MASK}, + {kIROp_BitXor, "xor", "^", "__BuiltinLogicalType", LOGICAL_MASK}, + {kIROp_Eql, "eql", "==", "__BuiltinType", ANY_MASK | BOOL_RESULT}, + {kIROp_Neq, "neq", "!=", "__BuiltinType", ANY_MASK | BOOL_RESULT}, + {kIROp_Greater, "greater", ">", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, + {kIROp_Less, "less", "<", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, + {kIROp_Geq, "geq", ">=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, + {kIROp_Leq, "leq", "<=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, + }; + + // Integer types that can be used in atomic operations in CUDA. + [[maybe_unused]] + static const char* kCudaAtomicIntegerTypes[] = { "int", "uint", "uint64_t", "int64_t" }; + + // Both the following functions use these macros. + // NOTE! They require a variable named path to emit the #line correctly if in source file. +#define SLANG_RAW(TEXT) sb << TEXT; +#define SLANG_SPLICE(EXPR) sb << (EXPR); + +#define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__+1) << " \"" << path << "\"\n" + + ComPtr Session::getCoreLibraryCode() + { +#if SLANG_EMBED_CORE_MODULE_SOURCE + if (!coreLibraryCode) + { + StringBuilder sb; + const String path = getStdlibPath(); + #include "core.meta.slang.h" + coreLibraryCode = StringBlob::moveCreate(sb); + } +#endif + return coreLibraryCode; + } + + ComPtr Session::getHLSLLibraryCode() + { +#if SLANG_EMBED_CORE_MODULE_SOURCE + if (!hlslLibraryCode) + { + const String path = getStdlibPath(); + StringBuilder sb; + #include "hlsl.meta.slang.h" + hlslLibraryCode = StringBlob::moveCreate(sb); + } +#endif + return hlslLibraryCode; + } + + ComPtr Session::getAutodiffLibraryCode() + { +#if SLANG_EMBED_CORE_MODULE_SOURCE + if (!autodiffLibraryCode) + { + const String path = getStdlibPath(); + StringBuilder sb; + #include "diff.meta.slang.h" + autodiffLibraryCode = StringBlob::moveCreate(sb); + } +#endif + return autodiffLibraryCode; + } + + ComPtr Session::getGLSLLibraryCode() + { + if (!glslLibraryCode) + { + const String path = getStdlibPath(); + StringBuilder sb; + #include "glsl.meta.slang.h" + glslLibraryCode = StringBlob::moveCreate(sb); + } + return glslLibraryCode; + } +} diff --git a/source/slang-stdlib/slang-embedded-core-module.cpp b/source/slang-stdlib/slang-embedded-core-module.cpp new file mode 100644 index 000000000..ceebcb940 --- /dev/null +++ b/source/slang-stdlib/slang-embedded-core-module.cpp @@ -0,0 +1,26 @@ +#include "../core/slang-basic.h" +#include "../core/slang-array-view.h" +#include "../core/slang-blob.h" + +#ifdef SLANG_EMBED_CORE_MODULE + +static const uint8_t g_coreModule[] = +{ +# include "slang-core-module-generated.h" +}; + +static Slang::StaticBlob g_coreModuleBlob((const void*)g_coreModule, sizeof(g_coreModule)); + +SLANG_API ISlangBlob* slang_getEmbeddedCoreModule() +{ + return &g_coreModuleBlob; +} + +#else + +SLANG_API ISlangBlob* slang_getEmbeddedCoreModule() +{ + return nullptr; +} + +#endif diff --git a/source/slang-stdlib/slang-embedded-stdlib-source.cpp b/source/slang-stdlib/slang-embedded-stdlib-source.cpp deleted file mode 100644 index d77126c94..000000000 --- a/source/slang-stdlib/slang-embedded-stdlib-source.cpp +++ /dev/null @@ -1,338 +0,0 @@ -#include "slang-compiler.h" -#include "slang-ir.h" -#include "slang-ir-util.h" -#include "slang-stdlib-textures.h" - -#define STRINGIZE(x) STRINGIZE2(x) -#define STRINGIZE2(x) #x -#define LINE_STRING STRINGIZE(__LINE__) - -namespace Slang -{ - // We are going to generate the stdlib source code from a more compact - // description. For example, we need to generate all the `operator` - // declarations for the basic unary and binary math operations on - // builtin types. To do this, we will make a big array of all these - // types, and associate them with data on their categories/capabilities - // so that we generate only the correct operations. - // - enum - { - SINT_MASK = 1 << 0, - FLOAT_MASK = 1 << 1, - BOOL_RESULT = 1 << 2, - BOOL_MASK = 1 << 3, - UINT_MASK = 1 << 4, - - INT_MASK = SINT_MASK | UINT_MASK, - ARITHMETIC_MASK = INT_MASK | FLOAT_MASK, - LOGICAL_MASK = INT_MASK | BOOL_MASK, - ANY_MASK = INT_MASK | FLOAT_MASK | BOOL_MASK, - }; - - // We are going to declare initializers that allow for conversion between - // all of our base types, and we need a way to priotize those conversion - // by giving them different costs. Rather than maintain a hard-coded table - // of N^2 costs for N basic types, we are going to try to do things a bit - // more systematically. - // - // Every base type will be given a "kind" and a "rank" for conversion. - // The kind will classify it as signed/unsigned/float, and the rank will - // classify it by its logical bit size (with a distinct rank for pointer-sized - // types that logically sits between 32- and 64-bit types). - // - enum BaseTypeConversionKind : uint8_t - { - kBaseTypeConversionKind_Signed, - kBaseTypeConversionKind_Unsigned, - kBaseTypeConversionKind_Float, - kBaseTypeConversionKind_Error, - }; - enum BaseTypeConversionRank : uint8_t - { - kBaseTypeConversionRank_Bool, - kBaseTypeConversionRank_Int8, - kBaseTypeConversionRank_Int16, - kBaseTypeConversionRank_Int32, - kBaseTypeConversionRank_IntPtr, - kBaseTypeConversionRank_Int64, - kBaseTypeConversionRank_Error, - }; - - // Here we declare the table of all our builtin types, so that we can generate all the relevant declarations. - // - struct BaseTypeConversionInfo - { - char const* name; - BaseType tag; - unsigned flags; - BaseTypeConversionKind conversionKind; - BaseTypeConversionRank conversionRank; - }; - static const BaseTypeConversionInfo kBaseTypes[] = { - // TODO: `void` really shouldn't be in the `BaseType` enumeration, since it behaves so differently across the board - { "void", BaseType::Void, 0, kBaseTypeConversionKind_Error, kBaseTypeConversionRank_Error}, - - { "bool", BaseType::Bool, BOOL_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Bool }, - - { "int8_t", BaseType::Int8, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int8}, - { "int16_t", BaseType::Int16, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int16}, - { "int", BaseType::Int, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int32}, - { "int64_t", BaseType::Int64, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_Int64}, - { "intptr_t", BaseType::IntPtr, SINT_MASK, kBaseTypeConversionKind_Signed, kBaseTypeConversionRank_IntPtr}, - - - { "half", BaseType::Half, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int16}, - { "float", BaseType::Float, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int32}, - { "double", BaseType::Double, FLOAT_MASK, kBaseTypeConversionKind_Float, kBaseTypeConversionRank_Int64}, - - { "uint8_t", BaseType::UInt8, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int8}, - { "uint16_t", BaseType::UInt16, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int16}, - { "uint", BaseType::UInt, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int32}, - { "uint64_t", BaseType::UInt64, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_Int64}, - { "uintptr_t", BaseType::UIntPtr, UINT_MASK, kBaseTypeConversionKind_Unsigned, kBaseTypeConversionRank_IntPtr}, - - }; - - void Session::finalizeSharedASTBuilder() - { - // Force creation of all builtin types so we can make sure - // they are created by the builtin AST builder instead of - // some user linkage's ast builder. This avoid the problem - // of storing a reference to these global types that are - // owned by a user linkage that gets deleted with the linkage. - // - globalAstBuilder->getNoneType(); - globalAstBuilder->getNullPtrType(); - globalAstBuilder->getBottomType(); - globalAstBuilder->getErrorType(); - globalAstBuilder->getInitializerListType(); - globalAstBuilder->getOverloadedType(); - globalAstBuilder->getStringType(); - globalAstBuilder->getEnumTypeType(); - globalAstBuilder->getDiffInterfaceType(); - globalAstBuilder->getSharedASTBuilder()->getDynamicType(); - globalAstBuilder->getSharedASTBuilder()->getDiffInterfaceType(); - globalAstBuilder->getSharedASTBuilder()->getNativeStringType(); - for (auto& baseType : kBaseTypes) - globalAstBuilder->getBuiltinType(baseType.tag); - } - - - // Given two base types, we need to be able to compute the cost of converting between them. - ConversionCost getBaseTypeConversionCost( - BaseTypeConversionInfo const& toInfo, - BaseTypeConversionInfo const& fromInfo) - { - if(toInfo.conversionKind == fromInfo.conversionKind - && toInfo.conversionRank == fromInfo.conversionRank) - { - // Thse should represent the exact same type. - return kConversionCost_None; - } - - // Conversions within the same kind are easist to handle - if (toInfo.conversionKind == fromInfo.conversionKind) - { - // If we are converting to a "larger" type, then - // we are doing a lossless promotion, and otherwise - // we are doing a demotion. - if (toInfo.conversionRank > fromInfo.conversionRank) - return kConversionCost_RankPromotion; - else - return kConversionCost_GeneralConversion; - } - else if (fromInfo.tag == BaseType::Bool && toInfo.tag == BaseType::Int) - { - return kConversionCost_BoolToInt; - } - - // If we are converting from an unsigned integer type to - // a signed integer type that is guaranteed to be larger, - // then that is also a lossless promotion. - // - // There is one additional wrinkle here, which is that - // a conversion from a 32-bit unsigned integer to a - // "pointer-sized" signed integer should be treated - // as unsafe, because the pointer size might also be - // 32 bits. - // - // The same basic exemption applied when converting - // *from* a pointer-sized unsigned integer. - else if(toInfo.conversionKind == kBaseTypeConversionKind_Signed - && fromInfo.conversionKind == kBaseTypeConversionKind_Unsigned - && toInfo.conversionRank > fromInfo.conversionRank - && toInfo.conversionRank != kBaseTypeConversionRank_IntPtr - && fromInfo.conversionRank != kBaseTypeConversionRank_IntPtr) - { - return kConversionCost_UnsignedToSignedPromotion; - } - // Same-size unsigned to signed integer conversion. - else if (toInfo.conversionKind == kBaseTypeConversionKind_Signed - && fromInfo.conversionKind == kBaseTypeConversionKind_Unsigned - && toInfo.conversionRank == fromInfo.conversionRank - && toInfo.conversionRank != kBaseTypeConversionRank_IntPtr - && fromInfo.conversionRank != kBaseTypeConversionRank_IntPtr) - { - return kConversionCost_SameSizeUnsignedToSignedConversion; - } - - // Conversion from signed to unsigned is always lossy, - // but it is preferred over conversions from unsigned - // to signed, for same-size types. - else if(toInfo.conversionKind == kBaseTypeConversionKind_Unsigned - && fromInfo.conversionKind == kBaseTypeConversionKind_Signed - && toInfo.conversionRank >= fromInfo.conversionRank) - { - return kConversionCost_SignedToUnsignedConversion; - } - - // Conversion from an integer to a floating-point type - // is never considered a promotion (even when the value - // would fit in the available mantissa bits). - // If the destination type is at least 32 bits we consider - // this a reasonably good conversion, though. - // - // Note that this means we do *not* consider implicit - // conversion to `half` as a good conversion, even for small - // types. This makes sense because we relaly want to prefer - // conversion to `float` as the default. - else if (toInfo.conversionKind == kBaseTypeConversionKind_Float - && toInfo.conversionRank >= kBaseTypeConversionRank_Int32 - && fromInfo.conversionRank >= kBaseTypeConversionRank_Int8) - { - return kConversionCost_IntegerToFloatConversion; - } - else if (toInfo.conversionKind == kBaseTypeConversionKind_Float - && toInfo.conversionRank >= kBaseTypeConversionRank_Int16 - && fromInfo.conversionRank >= kBaseTypeConversionRank_Int8) - { - return kConversionCost_IntegerToHalfConversion; - } - // All other cases are considered as "general" conversions, - // where we don't consider any one conversion better than - // any others. - else - { - return kConversionCost_GeneralConversion; - } - } - - IROp getBaseTypeConversionOp( - BaseTypeConversionInfo const& toInfo, - BaseTypeConversionInfo const& fromInfo) - { - if (toInfo.tag == fromInfo.tag) - return kIROp_Nop; - - IROp intrinsicOpCode = kIROp_Nop; - auto toStyle = getTypeStyle(toInfo.tag); - auto fromStyle = getTypeStyle(fromInfo.tag); - if (toStyle == kIROp_BoolType) toStyle = kIROp_IntType; - if (fromStyle == kIROp_BoolType) fromStyle = kIROp_IntType; - if (toStyle == kIROp_IntType && fromStyle == kIROp_IntType) - intrinsicOpCode = kIROp_IntCast; - if (toStyle == kIROp_IntType && fromStyle == kIROp_FloatType) - intrinsicOpCode = kIROp_CastFloatToInt; - if (toStyle == kIROp_FloatType && fromStyle == kIROp_IntType) - intrinsicOpCode = kIROp_CastIntToFloat; - if (toStyle == kIROp_FloatType && fromStyle == kIROp_FloatType) - intrinsicOpCode = kIROp_FloatCast; - return intrinsicOpCode; - } - - struct IntrinsicOpInfo { IROp opCode; char const* funcName; char const* opName; char const* interface; unsigned flags; }; - - [[maybe_unused]] - static const IntrinsicOpInfo intrinsicUnaryOps[] = { - { kIROp_Neg, "neg", "-", "__BuiltinArithmeticType", ARITHMETIC_MASK }, - { kIROp_Not, "logicalNot", "!", nullptr, BOOL_MASK | BOOL_RESULT }, - { kIROp_BitNot, "not", "~", "__BuiltinLogicalType", INT_MASK }, - }; - - [[maybe_unused]] - static const IntrinsicOpInfo intrinsicBinaryOps[] = { - {kIROp_Add, "add", "+", "__BuiltinArithmeticType", ARITHMETIC_MASK}, - {kIROp_Sub, "sub", "-", "__BuiltinArithmeticType", ARITHMETIC_MASK}, - {kIROp_Mul, "mul", "*", "__BuiltinArithmeticType", ARITHMETIC_MASK}, - {kIROp_Div, "div", "/", "__BuiltinArithmeticType", ARITHMETIC_MASK}, - {kIROp_IRem, "irem", "%", "__BuiltinIntegerType", INT_MASK}, - {kIROp_FRem, "frem", "%", "__BuiltinFloatingPointType", FLOAT_MASK}, - {kIROp_And, "logicalAnd", "&&", nullptr, BOOL_MASK | BOOL_RESULT}, - {kIROp_Or, "logicalOr", "||", nullptr, BOOL_MASK | BOOL_RESULT}, - {kIROp_BitAnd, "and", "&", "__BuiltinLogicalType", LOGICAL_MASK}, - {kIROp_BitOr, "or", "|", "__BuiltinLogicalType", LOGICAL_MASK}, - {kIROp_BitXor, "xor", "^", "__BuiltinLogicalType", LOGICAL_MASK}, - {kIROp_Eql, "eql", "==", "__BuiltinType", ANY_MASK | BOOL_RESULT}, - {kIROp_Neq, "neq", "!=", "__BuiltinType", ANY_MASK | BOOL_RESULT}, - {kIROp_Greater, "greater", ">", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, - {kIROp_Less, "less", "<", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, - {kIROp_Geq, "geq", ">=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, - {kIROp_Leq, "leq", "<=", "__BuiltinArithmeticType", ARITHMETIC_MASK | BOOL_RESULT}, - }; - - // Integer types that can be used in atomic operations in CUDA. - [[maybe_unused]] - static const char* kCudaAtomicIntegerTypes[] = { "int", "uint", "uint64_t", "int64_t" }; - - // Both the following functions use these macros. - // NOTE! They require a variable named path to emit the #line correctly if in source file. -#define SLANG_RAW(TEXT) sb << TEXT; -#define SLANG_SPLICE(EXPR) sb << (EXPR); - -#define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__+1) << " \"" << path << "\"\n" - - ComPtr Session::getCoreLibraryCode() - { -#if SLANG_EMBED_STDLIB_SOURCE - if (!coreLibraryCode) - { - StringBuilder sb; - const String path = getStdlibPath(); - #include "core.meta.slang.h" - coreLibraryCode = StringBlob::moveCreate(sb); - } -#endif - return coreLibraryCode; - } - - ComPtr Session::getHLSLLibraryCode() - { -#if SLANG_EMBED_STDLIB_SOURCE - if (!hlslLibraryCode) - { - const String path = getStdlibPath(); - StringBuilder sb; - #include "hlsl.meta.slang.h" - hlslLibraryCode = StringBlob::moveCreate(sb); - } -#endif - return hlslLibraryCode; - } - - ComPtr Session::getAutodiffLibraryCode() - { -#if SLANG_EMBED_STDLIB_SOURCE - if (!autodiffLibraryCode) - { - const String path = getStdlibPath(); - StringBuilder sb; - #include "diff.meta.slang.h" - autodiffLibraryCode = StringBlob::moveCreate(sb); - } -#endif - return autodiffLibraryCode; - } - - ComPtr Session::getGLSLLibraryCode() - { - if (!glslLibraryCode) - { - const String path = getStdlibPath(); - StringBuilder sb; - #include "glsl.meta.slang.h" - glslLibraryCode = StringBlob::moveCreate(sb); - } - return glslLibraryCode; - } -} diff --git a/source/slang-stdlib/slang-embedded-stdlib.cpp b/source/slang-stdlib/slang-embedded-stdlib.cpp deleted file mode 100644 index 83e4a8c70..000000000 --- a/source/slang-stdlib/slang-embedded-stdlib.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "../core/slang-basic.h" -#include "../core/slang-array-view.h" -#include "../core/slang-blob.h" - -#ifdef SLANG_EMBED_STDLIB - -static const uint8_t g_coreModule[] = -{ -# include "slang-stdlib-generated.h" -}; - -static Slang::StaticBlob g_coreModuleBlob((const void*)g_coreModule, sizeof(g_coreModule)); - -SLANG_API ISlangBlob* slang_getEmbeddedCoreModule() -{ - return &g_coreModuleBlob; -} - -#else - -SLANG_API ISlangBlob* slang_getEmbeddedCoreModule() -{ - return nullptr; -} - -#endif diff --git a/source/slang/CMakeLists.txt b/source/slang/CMakeLists.txt index 8e3be2069..a08ad1efc 100644 --- a/source/slang/CMakeLists.txt +++ b/source/slang/CMakeLists.txt @@ -205,22 +205,22 @@ set(slang_public_lib_args ${slang_SOURCE_DIR}/include/slang*.h ${CMAKE_CURRENT_BINARY_DIR}/slang-version-header/*.h LINK_WITH_PRIVATE - $,slang-embedded-stdlib,slang-no-embedded-stdlib> - $,slang-embedded-stdlib-source,slang-no-embedded-stdlib-source> + $,slang-embedded-core-module,slang-no-embedded-core-module> + $,slang-embedded-core-module-source,slang-no-embedded-core-module-source> INSTALL ) # -# Minimal static slang used in generating the embedded stdlib +# Minimal static slang used in generating the embedded core module # # # Slang itself # -if(NOT SLANG_EMBED_STDLIB) - # If we're not embedding stdlib we can just do a normal build of slang, - # including all the options, this can also serve as our no embedded stdlib +if(NOT SLANG_EMBED_CORE_MODULE) + # If we're not embedding core module we can just do a normal build of slang, + # including all the options, this can also serve as our no embedded core module # library for slang-bootstrap (not that we need that anyway) slang_add_target( . @@ -231,10 +231,10 @@ if(NOT SLANG_EMBED_STDLIB) ${slang_public_lib_args} INSTALL_COMPONENT generators ) - add_library(slang-without-embedded-stdlib ALIAS slang) + add_library(slang-without-embedded-core-module ALIAS slang) else() - # However if we're embedding stdlib, we need to make two different - # libraries, one with the embedded stdlib and one without, so first define + # However if we're embedding core module, we need to make two different + # libraries, one with the embedded core module and one without, so first define # the shared objects as one target so we don't build them twice. slang_add_target( . @@ -251,12 +251,12 @@ else() ${slang_interface_args} NO_SOURCE TARGET_NAME - slang-without-embedded-stdlib + slang-without-embedded-core-module EXCLUDE_FROM_ALL LINK_WITH_PRIVATE slang-common-objects - slang-no-embedded-stdlib - slang-embedded-stdlib-source + slang-no-embedded-core-module + slang-embedded-core-module-source OUTPUT_DIR generators FOLDER generators INSTALL_COMPONENT generators diff --git a/source/slang/slang-core-module-textures.cpp b/source/slang/slang-core-module-textures.cpp new file mode 100644 index 000000000..a74a954d5 --- /dev/null +++ b/source/slang/slang-core-module-textures.cpp @@ -0,0 +1,505 @@ +#include "slang-core-module-textures.h" +#include + +#define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__+1) << " \"slang-core-module-textures.cpp\"\n" + +namespace Slang +{ + +// Concatenate anything which can be passed to a StringBuilder +template +String cat(const Ts&... xs) +{ + return (StringBuilder{} << ... << xs); +}; + +// +// Utilities +// + +const auto indentWidth = 4; +static const char spaces[] = " "; +static_assert(SLANG_COUNT_OF(spaces) % indentWidth == 1); + +struct BraceScope +{ + BraceScope(const char*& i, StringBuilder& sb, const char* end = "\n") + :i(i), sb(sb), end(end) + { + // If we hit this assert, it means that we are indenting too deep and + // need more spaces in 'spaces' above. + SLANG_ASSERT(i != spaces); + sb << i << "{\n"; + i -= indentWidth; + } + ~BraceScope() + { + // If we hit this assert, it means that we've got a bug unindenting + // more than we've indented. + SLANG_ASSERT(*i != '\0'); + i += indentWidth; + sb << i << "}" << end; + } + const char*& i; + StringBuilder& sb; + const char* end; +}; + +TextureTypeInfo::TextureTypeInfo( + BaseTextureShapeInfo const& base, + bool isArray, + bool isMultisample, + bool isShadow, + StringBuilder& inSB, + String const& inPath) + : base(base) + , isArray(isArray) + , isMultisample(isMultisample) + , isShadow(isShadow) + , sb(inSB) + , path(inPath) +{ + i = spaces + SLANG_COUNT_OF(spaces) - 1; +} + +void TextureTypeInfo::writeFuncBody( + const char* funcName, + const String& glsl, + const String& cuda, + const String& spirvDefault, + const String& spirvRWDefault, + const String& spirvCombined, + const String& metal, + const String& wgsl) +{ + BraceScope funcScope{i, sb}; + { + sb << i << "__target_switch\n"; + BraceScope switchScope{i, sb}; + sb << i << "case cpp:\n"; + sb << i << "case hlsl:\n"; + sb << i << "__intrinsic_asm \"." << funcName << "\";\n"; + if(glsl.getLength()) + { + sb << i << "case glsl:\n"; + if (glsl.startsWith("if")) + sb << glsl; + else + sb << i << "__intrinsic_asm \"" << glsl << "\";\n"; + } + if(cuda.getLength()) + { + sb << i << "case cuda:\n"; + sb << i << "__intrinsic_asm \"" << cuda << "\";\n"; + } + if (metal.getLength()) + { + sb << i << "case metal:\n"; + sb << i << "__intrinsic_asm \"" << metal << "\";\n"; + } + if (spirvDefault.getLength() && spirvCombined.getLength()) + { + sb << i << "case spirv:\n"; + sb << i << "if (access == " << kStdlibResourceAccessReadWrite << ")\n"; + sb << i << "return spirv_asm\n"; + { + BraceScope spirvRWScope{ i, sb, ";\n" }; + sb << spirvRWDefault << "\n"; + } + sb << i << "else if (isCombined != 0)\n"; + sb << i << "{\n"; + { + sb << i << "return spirv_asm\n"; + BraceScope spirvCombinedScope{i, sb, ";\n"}; + sb << spirvCombined << "\n"; + } + sb << i << "}\n"; + sb << i << "else\n"; + sb << i << "{\n"; + { + sb << i << "return spirv_asm\n"; + BraceScope spirvDefaultScope{i, sb, ";\n"}; + sb << spirvDefault << "\n"; + } + sb << i << "}\n"; + } + if (wgsl.getLength()) + { + sb << i << "case wgsl:\n"; + sb << i << "__intrinsic_asm \"" << wgsl << "\";\n"; + } + } +} + +void TextureTypeInfo::writeFuncWithSig( + const char* funcName, + const String& sig, + const String& glsl, + const String& spirvDefault, + const String& spirvRWDefault, + const String& spirvCombined, + const String& cuda, + const String& metal, + const String& wgsl, + const ReadNoneMode readNoneMode) +{ + if (readNoneMode == ReadNoneMode::Always) + sb << i << "[__readNone]\n"; + sb << i << "[ForceInline]\n"; + sb << i << sig << "\n"; + writeFuncBody(funcName, glsl, cuda, spirvDefault, spirvRWDefault, spirvCombined, metal, wgsl); + sb << "\n"; +} + +void TextureTypeInfo::writeFunc( + const char* returnType, + const char* funcName, + const String& params, + const String& glsl, + const String& spirvDefault, + const String& spirvRWDefault, + const String& spirvCombined, + const String& cuda, + const String& metal, + const String& wgsl, + const ReadNoneMode readNoneMode) +{ + writeFuncWithSig( + funcName, + cat(returnType, " ", funcName, "(", params, ")"), + glsl, + spirvDefault, + spirvRWDefault, + spirvCombined, + cuda, + metal, + wgsl, + readNoneMode + ); +} + +void TextureTypeInfo::writeGetDimensionFunctions() +{ + static const char* kComponentNames[]{ "x", "y", "z", "w" }; + + SlangResourceShape baseShape = base.baseShape; + + // `GetDimensions` + const char* dimParamTypes[] = { "out float ", "out int ", "out uint " }; + const char* dimParamTypesInner[] = { "float", "int", "uint" }; + for (int tid = 0; tid < 3; tid++) + { + auto t = dimParamTypes[tid]; + auto rawT = dimParamTypesInner[tid]; + + for (int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo) + { + if (includeMipInfo && isMultisample) + { + continue; + } + + int sizeDimCount = 0; + StringBuilder params; + int paramCount = 0; + + StringBuilder metal; + const char* metalMipLevel = "0"; + + StringBuilder wgsl; + wgsl << "{"; + + if (includeMipInfo) + { + ++paramCount; + params << "uint mipLevel,"; + + if (baseShape != SLANG_TEXTURE_1D) + metalMipLevel = "$1"; + } + + switch (baseShape) + { + case SLANG_TEXTURE_1D: + ++paramCount; + params << t << "width"; + metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; + wgsl << "($" << String(paramCount) << ") = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; + + sizeDimCount = 1; + break; + + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: + ++paramCount; + params << t << "width,"; + metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; + wgsl << "var dim = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; + wgsl << "($" << String(paramCount) << ") = dim.x;"; + + ++paramCount; + params << t << "height"; + metal << "(*($" << String(paramCount) << ") = $0.get_height(" << String(metalMipLevel) << ")),"; + wgsl << "($" << String(paramCount) << ") = dim.y;"; + + sizeDimCount = 2; + break; + + case SLANG_TEXTURE_3D: + ++paramCount; + params << t << "width,"; + metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; + wgsl << "var dim = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; + wgsl << "($" << String(paramCount) << ") = dim.x;"; + + ++paramCount; + params << t << "height,"; + metal << "(*($" << String(paramCount) << ") = $0.get_height(" << String(metalMipLevel) << ")),"; + wgsl << "($" << String(paramCount) << ") = dim.y;"; + + ++paramCount; + params << t << "depth"; + metal << "(*($" << String(paramCount) << ") = $0.get_depth(" << String(metalMipLevel) << ")),"; + wgsl << "($" << String(paramCount) << ") = dim.z;"; + + sizeDimCount = 3; + break; + + default: + assert(!"unexpected"); + break; + } + + if (isArray) + { + ++sizeDimCount; + ++paramCount; + params << ", " << t << "elements"; + metal << "(*($" << String(paramCount) << ") = $0.get_array_size()),"; + wgsl << "($" << String(paramCount) << ") = textureNumLayers($0);"; + } + + if (isMultisample) + { + ++paramCount; + params << ", " << t << "sampleCount"; + metal << "(*($" << String(paramCount) << ") = $0.get_num_samples()),"; + wgsl << "($" << String(paramCount) << ") = textureNumSamples($0);"; + } + + if (includeMipInfo) + { + ++paramCount; + params << ", " << t << "numberOfLevels"; + metal << "(*($" << String(paramCount) << ") = $0.get_num_mip_levels()),"; + wgsl << "($" << String(paramCount) << ") = textureNumLevels($0);"; + } + + metal.reduceLength(metal.getLength() - 1); // drop the last comma + wgsl << "}"; + + StringBuilder glsl; + { + auto emitIntrinsic = [&](UnownedStringSlice funcName, bool useLodStr) + { + int aa = 1; + StringBuilder opStrSB; + opStrSB << " = " << funcName << "($0"; + if (useLodStr) + { + String lodStr = ", 0"; + if (includeMipInfo) + { + int mipLevelArg = aa++; + lodStr = ", int($"; + lodStr.append(mipLevelArg); + lodStr.append(")"); + } + opStrSB << lodStr; + } + auto opStr = opStrSB.produceString(); + int cc = 0; + switch (baseShape) + { + case SLANG_TEXTURE_1D: + glsl << "($" << aa++ << opStr << ")"; + if (isArray) + { + glsl << ".x"; + } + glsl << ")"; + cc = 1; + break; + + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: + glsl << "($" << aa++ << opStr << ").x)"; + glsl << ", ($" << aa++ << opStr << ").y)"; + cc = 2; + break; + + case SLANG_TEXTURE_3D: + glsl << "($" << aa++ << opStr << ").x)"; + glsl << ", ($" << aa++ << opStr << ").y)"; + glsl << ", ($" << aa++ << opStr << ").z)"; + cc = 3; + break; + + default: + SLANG_UNEXPECTED("unhandled resource shape"); + break; + } + + if (isArray) + { + glsl << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")"; + } + + if (isMultisample) + { + glsl << ", ($" << aa++ << " = textureSamples($0))"; + } + + if (includeMipInfo) + { + glsl << ", ($" << aa++ << " = textureQueryLevels($0))"; + } + }; + glsl << "if (access == " << kStdlibResourceAccessReadOnly << ") __intrinsic_asm \""; + emitIntrinsic(toSlice("textureSize"), !isMultisample); + glsl << "\";\n"; + glsl << "__intrinsic_asm \""; + emitIntrinsic(toSlice("imageSize"), false); + glsl << "\";\n"; + } + + // SPIRV ASM generation + auto generateSpirvAsm = [&](StringBuilder& spirv, bool isRW, UnownedStringSlice imageVar) + { + spirv << "%vecSize:$$uint"; + if (sizeDimCount > 1) spirv << sizeDimCount; + spirv << " = "; + if (isMultisample || isRW) + spirv << "OpImageQuerySize " << imageVar << ";"; + else + spirv << "OpImageQuerySizeLod " << imageVar <<" $0;"; + + auto convertAndStore = [&](UnownedStringSlice uintSourceVal, const char* destParam) + { + if (UnownedStringSlice(rawT) == "uint") + { + spirv << "OpStore &" << destParam << " %" << uintSourceVal << ";"; + } + else + { + if (UnownedStringSlice(rawT) == "int") + { + spirv << "%c_" << uintSourceVal << " : $$" << rawT << " = OpBitcast %" << uintSourceVal << "; "; + } + else + { + spirv << "%c_" << uintSourceVal << " : $$" << rawT << " = OpConvertUToF %" << uintSourceVal << "; "; + } + spirv << "OpStore &" << destParam << "%c_" << uintSourceVal << ";"; + } + }; + auto extractSizeComponent = [&](int componentId, const char* destParam) + { + String elementVal = String("_") + destParam; + if (sizeDimCount == 1) + { + spirv << "%" << elementVal << " : $$uint = OpCopyObject %vecSize; "; + } + else + { + spirv << "%" << elementVal << " : $$uint = OpCompositeExtract %vecSize " << componentId << "; "; + } + convertAndStore(elementVal.getUnownedSlice(), destParam); + }; + switch (baseShape) + { + case SLANG_TEXTURE_1D: + extractSizeComponent(0, "width"); + break; + + case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: + extractSizeComponent(0, "width"); + extractSizeComponent(1, "height"); + break; + + case SLANG_TEXTURE_3D: + extractSizeComponent(0, "width"); + extractSizeComponent(1, "height"); + extractSizeComponent(2, "depth"); + break; + + default: + assert(!"unexpected"); + break; + } + + if (isArray) + { + extractSizeComponent(sizeDimCount - 1, "elements"); + } + + if (isMultisample) + { + spirv << "%_sampleCount : $$uint = OpImageQuerySamples" << imageVar << ";"; + convertAndStore(UnownedStringSlice("_sampleCount"), "sampleCount"); + } + + if (includeMipInfo) + { + spirv << "%_levelCount : $$uint = OpImageQueryLevels" << imageVar << ";"; + convertAndStore(UnownedStringSlice("_levelCount"), "numberOfLevels"); + } + }; + StringBuilder spirvCombined; + { + spirvCombined << "OpCapability ImageQuery; "; + spirvCombined << "%image:__imageType(this) = OpImage $this; "; + generateSpirvAsm(spirvCombined, false, toSlice("%image")); + } + + StringBuilder spirvDefault; + { + spirvDefault << "OpCapability ImageQuery; "; + generateSpirvAsm(spirvDefault, false, toSlice("$this")); + } + + StringBuilder spirvRWDefault; + { + spirvRWDefault << "OpCapability ImageQuery; "; + generateSpirvAsm(spirvRWDefault, true, toSlice("$this")); + } + + sb << " __glsl_version(450)\n"; + sb << " __glsl_extension(GL_EXT_samplerless_texture_functions)\n"; + + sb << " [require(cpp"; + if (glsl.getLength()) sb << "_glsl"; + sb << "_hlsl"; + if (metal.getLength()) sb << "_metal"; + if (spirvDefault.getLength() && spirvCombined.getLength()) sb << "_spirv"; + if (wgsl.getLength()) sb << "_wgsl"; + sb << ", texture_sm_4_1)]\n"; + + writeFunc( + "void", + "GetDimensions", + params, + glsl, + spirvDefault, + spirvRWDefault, + spirvCombined, + "", + metal, + wgsl, + ReadNoneMode::Always); + } + } +} + +} diff --git a/source/slang/slang-core-module-textures.h b/source/slang/slang-core-module-textures.h new file mode 100644 index 000000000..a521a44d3 --- /dev/null +++ b/source/slang/slang-core-module-textures.h @@ -0,0 +1,105 @@ +#pragma once + +#include "slang-ir.h" +#include "slang-type-system-shared.h" +#include "../core/slang-string.h" + +namespace Slang +{ + +static const struct BaseTextureShapeInfo { + char const* shapeName; + SlangResourceShape baseShape; + int coordCount; +} kBaseTextureShapes[] = { + { "1D", SLANG_TEXTURE_1D, 1 }, + { "2D", SLANG_TEXTURE_2D, 2 }, + { "3D", SLANG_TEXTURE_3D, 3 }, + { "Cube", SLANG_TEXTURE_CUBE, 3 }, +}; + +static const struct BaseTextureAccessInfo { + char const* name; + SlangResourceAccess access; +} kBaseTextureAccessLevels[] = { + { "", SLANG_RESOURCE_ACCESS_READ }, + { "RW", SLANG_RESOURCE_ACCESS_READ_WRITE }, + { "RasterizerOrdered", SLANG_RESOURCE_ACCESS_RASTER_ORDERED }, + { "Feedback", SLANG_RESOURCE_ACCESS_FEEDBACK }, +}; + +struct TextureTypeInfo +{ + TextureTypeInfo( + BaseTextureShapeInfo const& base, + bool isArray, + bool isMultisample, + bool isShadow, + StringBuilder& inSB, + String const& inPath); + + BaseTextureShapeInfo const& base; + bool isArray; + bool isMultisample; + bool isShadow; + StringBuilder& sb; + String path; + + void emitTypeDecl(); + +public: + // + // Functions for writing specific parts of a definition + // + void writeGetDimensionFunctions(); + + // + // More general utilities + // + enum class ReadNoneMode + { + Never, + Always + }; + + void writeFuncBody( + const char* funcName, + const String& glsl, + const String& cuda, + const String& spirvDefault, + const String& spirvRWDefault, + const String& spirvCombined, + const String& metal, + const String& wgsl + ); + void writeFuncWithSig( + const char* funcName, + const String& sig, + const String& glsl = String{}, + const String& spirvDefault = String{}, + const String& spirvRWDefault = String{}, + const String& spirvCombined = String{}, + const String& cuda = String{}, + const String& metal = String{}, + const String& wgsl = String{}, + const ReadNoneMode readNoneMode = ReadNoneMode::Never + ); + void writeFunc( + const char* returnType, + const char* funcName, + const String& params, + const String& glsl = String{}, + const String& spirvDefault = String{}, + const String& spirvRWDefault = String{}, + const String& spirvCombined = String{}, + const String& cuda = String{}, + const String& metal = String{}, + const String& wgsl = String{}, + const ReadNoneMode readNoneMode = ReadNoneMode::Never + ); + + // A pointer to a string representing the current level of indentation + const char* i; +}; + +} diff --git a/source/slang/slang-core-module.cpp b/source/slang/slang-core-module.cpp new file mode 100644 index 000000000..8867ba1c3 --- /dev/null +++ b/source/slang/slang-core-module.cpp @@ -0,0 +1,25 @@ +#include "slang-compiler.h" +#include "slang-ir.h" +#include "../core/slang-string-util.h" + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define LINE_STRING STRINGIZE(__LINE__) + +namespace Slang +{ + String Session::getStdlibPath() + { + if(stdlibPath.getLength() == 0) + { + // Make sure we have a line of text from __FILE__, that we'll extract the filename from + List lines; + StringUtil::calcLines(UnownedStringSlice::fromLiteral(__FILE__), lines); + SLANG_ASSERT(lines.getCount() > 0 && lines[0].getLength() > 0); + + // Make the path just the filename to remove issues around path being included on different targets + stdlibPath = Path::getFileName(lines[0]); + } + return stdlibPath; + } +} diff --git a/source/slang/slang-stdlib-textures.cpp b/source/slang/slang-stdlib-textures.cpp deleted file mode 100644 index c9b7598c7..000000000 --- a/source/slang/slang-stdlib-textures.cpp +++ /dev/null @@ -1,505 +0,0 @@ -#include "slang-stdlib-textures.h" -#include - -#define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__+1) << " \"slang-stdlib-textures.cpp\"\n" - -namespace Slang -{ - -// Concatenate anything which can be passed to a StringBuilder -template -String cat(const Ts&... xs) -{ - return (StringBuilder{} << ... << xs); -}; - -// -// Utilities -// - -const auto indentWidth = 4; -static const char spaces[] = " "; -static_assert(SLANG_COUNT_OF(spaces) % indentWidth == 1); - -struct BraceScope -{ - BraceScope(const char*& i, StringBuilder& sb, const char* end = "\n") - :i(i), sb(sb), end(end) - { - // If we hit this assert, it means that we are indenting too deep and - // need more spaces in 'spaces' above. - SLANG_ASSERT(i != spaces); - sb << i << "{\n"; - i -= indentWidth; - } - ~BraceScope() - { - // If we hit this assert, it means that we've got a bug unindenting - // more than we've indented. - SLANG_ASSERT(*i != '\0'); - i += indentWidth; - sb << i << "}" << end; - } - const char*& i; - StringBuilder& sb; - const char* end; -}; - -TextureTypeInfo::TextureTypeInfo( - BaseTextureShapeInfo const& base, - bool isArray, - bool isMultisample, - bool isShadow, - StringBuilder& inSB, - String const& inPath) - : base(base) - , isArray(isArray) - , isMultisample(isMultisample) - , isShadow(isShadow) - , sb(inSB) - , path(inPath) -{ - i = spaces + SLANG_COUNT_OF(spaces) - 1; -} - -void TextureTypeInfo::writeFuncBody( - const char* funcName, - const String& glsl, - const String& cuda, - const String& spirvDefault, - const String& spirvRWDefault, - const String& spirvCombined, - const String& metal, - const String& wgsl) -{ - BraceScope funcScope{i, sb}; - { - sb << i << "__target_switch\n"; - BraceScope switchScope{i, sb}; - sb << i << "case cpp:\n"; - sb << i << "case hlsl:\n"; - sb << i << "__intrinsic_asm \"." << funcName << "\";\n"; - if(glsl.getLength()) - { - sb << i << "case glsl:\n"; - if (glsl.startsWith("if")) - sb << glsl; - else - sb << i << "__intrinsic_asm \"" << glsl << "\";\n"; - } - if(cuda.getLength()) - { - sb << i << "case cuda:\n"; - sb << i << "__intrinsic_asm \"" << cuda << "\";\n"; - } - if (metal.getLength()) - { - sb << i << "case metal:\n"; - sb << i << "__intrinsic_asm \"" << metal << "\";\n"; - } - if (spirvDefault.getLength() && spirvCombined.getLength()) - { - sb << i << "case spirv:\n"; - sb << i << "if (access == " << kStdlibResourceAccessReadWrite << ")\n"; - sb << i << "return spirv_asm\n"; - { - BraceScope spirvRWScope{ i, sb, ";\n" }; - sb << spirvRWDefault << "\n"; - } - sb << i << "else if (isCombined != 0)\n"; - sb << i << "{\n"; - { - sb << i << "return spirv_asm\n"; - BraceScope spirvCombinedScope{i, sb, ";\n"}; - sb << spirvCombined << "\n"; - } - sb << i << "}\n"; - sb << i << "else\n"; - sb << i << "{\n"; - { - sb << i << "return spirv_asm\n"; - BraceScope spirvDefaultScope{i, sb, ";\n"}; - sb << spirvDefault << "\n"; - } - sb << i << "}\n"; - } - if (wgsl.getLength()) - { - sb << i << "case wgsl:\n"; - sb << i << "__intrinsic_asm \"" << wgsl << "\";\n"; - } - } -} - -void TextureTypeInfo::writeFuncWithSig( - const char* funcName, - const String& sig, - const String& glsl, - const String& spirvDefault, - const String& spirvRWDefault, - const String& spirvCombined, - const String& cuda, - const String& metal, - const String& wgsl, - const ReadNoneMode readNoneMode) -{ - if (readNoneMode == ReadNoneMode::Always) - sb << i << "[__readNone]\n"; - sb << i << "[ForceInline]\n"; - sb << i << sig << "\n"; - writeFuncBody(funcName, glsl, cuda, spirvDefault, spirvRWDefault, spirvCombined, metal, wgsl); - sb << "\n"; -} - -void TextureTypeInfo::writeFunc( - const char* returnType, - const char* funcName, - const String& params, - const String& glsl, - const String& spirvDefault, - const String& spirvRWDefault, - const String& spirvCombined, - const String& cuda, - const String& metal, - const String& wgsl, - const ReadNoneMode readNoneMode) -{ - writeFuncWithSig( - funcName, - cat(returnType, " ", funcName, "(", params, ")"), - glsl, - spirvDefault, - spirvRWDefault, - spirvCombined, - cuda, - metal, - wgsl, - readNoneMode - ); -} - -void TextureTypeInfo::writeGetDimensionFunctions() -{ - static const char* kComponentNames[]{ "x", "y", "z", "w" }; - - SlangResourceShape baseShape = base.baseShape; - - // `GetDimensions` - const char* dimParamTypes[] = { "out float ", "out int ", "out uint " }; - const char* dimParamTypesInner[] = { "float", "int", "uint" }; - for (int tid = 0; tid < 3; tid++) - { - auto t = dimParamTypes[tid]; - auto rawT = dimParamTypesInner[tid]; - - for (int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo) - { - if (includeMipInfo && isMultisample) - { - continue; - } - - int sizeDimCount = 0; - StringBuilder params; - int paramCount = 0; - - StringBuilder metal; - const char* metalMipLevel = "0"; - - StringBuilder wgsl; - wgsl << "{"; - - if (includeMipInfo) - { - ++paramCount; - params << "uint mipLevel,"; - - if (baseShape != SLANG_TEXTURE_1D) - metalMipLevel = "$1"; - } - - switch (baseShape) - { - case SLANG_TEXTURE_1D: - ++paramCount; - params << t << "width"; - metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; - wgsl << "($" << String(paramCount) << ") = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; - - sizeDimCount = 1; - break; - - case SLANG_TEXTURE_2D: - case SLANG_TEXTURE_CUBE: - ++paramCount; - params << t << "width,"; - metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; - wgsl << "var dim = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; - wgsl << "($" << String(paramCount) << ") = dim.x;"; - - ++paramCount; - params << t << "height"; - metal << "(*($" << String(paramCount) << ") = $0.get_height(" << String(metalMipLevel) << ")),"; - wgsl << "($" << String(paramCount) << ") = dim.y;"; - - sizeDimCount = 2; - break; - - case SLANG_TEXTURE_3D: - ++paramCount; - params << t << "width,"; - metal << "(*($" << String(paramCount) << ") = $0.get_width(" << String(metalMipLevel) << ")),"; - wgsl << "var dim = textureDimensions($0" << (includeMipInfo ? ", $1" : "") << ");"; - wgsl << "($" << String(paramCount) << ") = dim.x;"; - - ++paramCount; - params << t << "height,"; - metal << "(*($" << String(paramCount) << ") = $0.get_height(" << String(metalMipLevel) << ")),"; - wgsl << "($" << String(paramCount) << ") = dim.y;"; - - ++paramCount; - params << t << "depth"; - metal << "(*($" << String(paramCount) << ") = $0.get_depth(" << String(metalMipLevel) << ")),"; - wgsl << "($" << String(paramCount) << ") = dim.z;"; - - sizeDimCount = 3; - break; - - default: - assert(!"unexpected"); - break; - } - - if (isArray) - { - ++sizeDimCount; - ++paramCount; - params << ", " << t << "elements"; - metal << "(*($" << String(paramCount) << ") = $0.get_array_size()),"; - wgsl << "($" << String(paramCount) << ") = textureNumLayers($0);"; - } - - if (isMultisample) - { - ++paramCount; - params << ", " << t << "sampleCount"; - metal << "(*($" << String(paramCount) << ") = $0.get_num_samples()),"; - wgsl << "($" << String(paramCount) << ") = textureNumSamples($0);"; - } - - if (includeMipInfo) - { - ++paramCount; - params << ", " << t << "numberOfLevels"; - metal << "(*($" << String(paramCount) << ") = $0.get_num_mip_levels()),"; - wgsl << "($" << String(paramCount) << ") = textureNumLevels($0);"; - } - - metal.reduceLength(metal.getLength() - 1); // drop the last comma - wgsl << "}"; - - StringBuilder glsl; - { - auto emitIntrinsic = [&](UnownedStringSlice funcName, bool useLodStr) - { - int aa = 1; - StringBuilder opStrSB; - opStrSB << " = " << funcName << "($0"; - if (useLodStr) - { - String lodStr = ", 0"; - if (includeMipInfo) - { - int mipLevelArg = aa++; - lodStr = ", int($"; - lodStr.append(mipLevelArg); - lodStr.append(")"); - } - opStrSB << lodStr; - } - auto opStr = opStrSB.produceString(); - int cc = 0; - switch (baseShape) - { - case SLANG_TEXTURE_1D: - glsl << "($" << aa++ << opStr << ")"; - if (isArray) - { - glsl << ".x"; - } - glsl << ")"; - cc = 1; - break; - - case SLANG_TEXTURE_2D: - case SLANG_TEXTURE_CUBE: - glsl << "($" << aa++ << opStr << ").x)"; - glsl << ", ($" << aa++ << opStr << ").y)"; - cc = 2; - break; - - case SLANG_TEXTURE_3D: - glsl << "($" << aa++ << opStr << ").x)"; - glsl << ", ($" << aa++ << opStr << ").y)"; - glsl << ", ($" << aa++ << opStr << ").z)"; - cc = 3; - break; - - default: - SLANG_UNEXPECTED("unhandled resource shape"); - break; - } - - if (isArray) - { - glsl << ", ($" << aa++ << opStr << ")." << kComponentNames[cc] << ")"; - } - - if (isMultisample) - { - glsl << ", ($" << aa++ << " = textureSamples($0))"; - } - - if (includeMipInfo) - { - glsl << ", ($" << aa++ << " = textureQueryLevels($0))"; - } - }; - glsl << "if (access == " << kStdlibResourceAccessReadOnly << ") __intrinsic_asm \""; - emitIntrinsic(toSlice("textureSize"), !isMultisample); - glsl << "\";\n"; - glsl << "__intrinsic_asm \""; - emitIntrinsic(toSlice("imageSize"), false); - glsl << "\";\n"; - } - - // SPIRV ASM generation - auto generateSpirvAsm = [&](StringBuilder& spirv, bool isRW, UnownedStringSlice imageVar) - { - spirv << "%vecSize:$$uint"; - if (sizeDimCount > 1) spirv << sizeDimCount; - spirv << " = "; - if (isMultisample || isRW) - spirv << "OpImageQuerySize " << imageVar << ";"; - else - spirv << "OpImageQuerySizeLod " << imageVar <<" $0;"; - - auto convertAndStore = [&](UnownedStringSlice uintSourceVal, const char* destParam) - { - if (UnownedStringSlice(rawT) == "uint") - { - spirv << "OpStore &" << destParam << " %" << uintSourceVal << ";"; - } - else - { - if (UnownedStringSlice(rawT) == "int") - { - spirv << "%c_" << uintSourceVal << " : $$" << rawT << " = OpBitcast %" << uintSourceVal << "; "; - } - else - { - spirv << "%c_" << uintSourceVal << " : $$" << rawT << " = OpConvertUToF %" << uintSourceVal << "; "; - } - spirv << "OpStore &" << destParam << "%c_" << uintSourceVal << ";"; - } - }; - auto extractSizeComponent = [&](int componentId, const char* destParam) - { - String elementVal = String("_") + destParam; - if (sizeDimCount == 1) - { - spirv << "%" << elementVal << " : $$uint = OpCopyObject %vecSize; "; - } - else - { - spirv << "%" << elementVal << " : $$uint = OpCompositeExtract %vecSize " << componentId << "; "; - } - convertAndStore(elementVal.getUnownedSlice(), destParam); - }; - switch (baseShape) - { - case SLANG_TEXTURE_1D: - extractSizeComponent(0, "width"); - break; - - case SLANG_TEXTURE_2D: - case SLANG_TEXTURE_CUBE: - extractSizeComponent(0, "width"); - extractSizeComponent(1, "height"); - break; - - case SLANG_TEXTURE_3D: - extractSizeComponent(0, "width"); - extractSizeComponent(1, "height"); - extractSizeComponent(2, "depth"); - break; - - default: - assert(!"unexpected"); - break; - } - - if (isArray) - { - extractSizeComponent(sizeDimCount - 1, "elements"); - } - - if (isMultisample) - { - spirv << "%_sampleCount : $$uint = OpImageQuerySamples" << imageVar << ";"; - convertAndStore(UnownedStringSlice("_sampleCount"), "sampleCount"); - } - - if (includeMipInfo) - { - spirv << "%_levelCount : $$uint = OpImageQueryLevels" << imageVar << ";"; - convertAndStore(UnownedStringSlice("_levelCount"), "numberOfLevels"); - } - }; - StringBuilder spirvCombined; - { - spirvCombined << "OpCapability ImageQuery; "; - spirvCombined << "%image:__imageType(this) = OpImage $this; "; - generateSpirvAsm(spirvCombined, false, toSlice("%image")); - } - - StringBuilder spirvDefault; - { - spirvDefault << "OpCapability ImageQuery; "; - generateSpirvAsm(spirvDefault, false, toSlice("$this")); - } - - StringBuilder spirvRWDefault; - { - spirvRWDefault << "OpCapability ImageQuery; "; - generateSpirvAsm(spirvRWDefault, true, toSlice("$this")); - } - - sb << " __glsl_version(450)\n"; - sb << " __glsl_extension(GL_EXT_samplerless_texture_functions)\n"; - - sb << " [require(cpp"; - if (glsl.getLength()) sb << "_glsl"; - sb << "_hlsl"; - if (metal.getLength()) sb << "_metal"; - if (spirvDefault.getLength() && spirvCombined.getLength()) sb << "_spirv"; - if (wgsl.getLength()) sb << "_wgsl"; - sb << ", texture_sm_4_1)]\n"; - - writeFunc( - "void", - "GetDimensions", - params, - glsl, - spirvDefault, - spirvRWDefault, - spirvCombined, - "", - metal, - wgsl, - ReadNoneMode::Always); - } - } -} - -} diff --git a/source/slang/slang-stdlib-textures.h b/source/slang/slang-stdlib-textures.h deleted file mode 100644 index a521a44d3..000000000 --- a/source/slang/slang-stdlib-textures.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "slang-ir.h" -#include "slang-type-system-shared.h" -#include "../core/slang-string.h" - -namespace Slang -{ - -static const struct BaseTextureShapeInfo { - char const* shapeName; - SlangResourceShape baseShape; - int coordCount; -} kBaseTextureShapes[] = { - { "1D", SLANG_TEXTURE_1D, 1 }, - { "2D", SLANG_TEXTURE_2D, 2 }, - { "3D", SLANG_TEXTURE_3D, 3 }, - { "Cube", SLANG_TEXTURE_CUBE, 3 }, -}; - -static const struct BaseTextureAccessInfo { - char const* name; - SlangResourceAccess access; -} kBaseTextureAccessLevels[] = { - { "", SLANG_RESOURCE_ACCESS_READ }, - { "RW", SLANG_RESOURCE_ACCESS_READ_WRITE }, - { "RasterizerOrdered", SLANG_RESOURCE_ACCESS_RASTER_ORDERED }, - { "Feedback", SLANG_RESOURCE_ACCESS_FEEDBACK }, -}; - -struct TextureTypeInfo -{ - TextureTypeInfo( - BaseTextureShapeInfo const& base, - bool isArray, - bool isMultisample, - bool isShadow, - StringBuilder& inSB, - String const& inPath); - - BaseTextureShapeInfo const& base; - bool isArray; - bool isMultisample; - bool isShadow; - StringBuilder& sb; - String path; - - void emitTypeDecl(); - -public: - // - // Functions for writing specific parts of a definition - // - void writeGetDimensionFunctions(); - - // - // More general utilities - // - enum class ReadNoneMode - { - Never, - Always - }; - - void writeFuncBody( - const char* funcName, - const String& glsl, - const String& cuda, - const String& spirvDefault, - const String& spirvRWDefault, - const String& spirvCombined, - const String& metal, - const String& wgsl - ); - void writeFuncWithSig( - const char* funcName, - const String& sig, - const String& glsl = String{}, - const String& spirvDefault = String{}, - const String& spirvRWDefault = String{}, - const String& spirvCombined = String{}, - const String& cuda = String{}, - const String& metal = String{}, - const String& wgsl = String{}, - const ReadNoneMode readNoneMode = ReadNoneMode::Never - ); - void writeFunc( - const char* returnType, - const char* funcName, - const String& params, - const String& glsl = String{}, - const String& spirvDefault = String{}, - const String& spirvRWDefault = String{}, - const String& spirvCombined = String{}, - const String& cuda = String{}, - const String& metal = String{}, - const String& wgsl = String{}, - const ReadNoneMode readNoneMode = ReadNoneMode::Never - ); - - // A pointer to a string representing the current level of indentation - const char* i; -}; - -} diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp deleted file mode 100644 index e28d95ad5..000000000 --- a/source/slang/slang-stdlib.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// slang-stdlib.cpp - -#include "slang-compiler.h" -#include "slang-ir.h" -#include "../core/slang-string-util.h" - -#define STRINGIZE(x) STRINGIZE2(x) -#define STRINGIZE2(x) #x -#define LINE_STRING STRINGIZE(__LINE__) - -namespace Slang -{ - String Session::getStdlibPath() - { - if(stdlibPath.getLength() == 0) - { - // Make sure we have a line of text from __FILE__, that we'll extract the filename from - List lines; - StringUtil::calcLines(UnownedStringSlice::fromLiteral(__FILE__), lines); - SLANG_ASSERT(lines.getCount() > 0 && lines[0].getLength() > 0); - - // Make the path just the filename to remove issues around path being included on different targets - stdlibPath = Path::getFileName(lines[0]); - } - return stdlibPath; - } -} -- cgit v1.2.3