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. --- .gitignore | 2 +- CMakeLists.txt | 8 +- docs/building.md | 4 +- 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 -- tools/CMakeLists.txt | 2 +- tools/slang-test/parse-diagnostic-util.cpp | 8 +- 17 files changed, 1068 insertions(+), 1070 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 diff --git a/.gitignore b/.gitignore index 1df808ba7..e407ed018 100644 --- a/.gitignore +++ b/.gitignore @@ -68,7 +68,7 @@ prelude/*.h.cpp /docs/Gemfile.lock /docs/Gemfile /docs/stdlib-reference -/source/slang/slang-stdlib-generated.h +/source/slang/slang-core-module-generated.h /examples/heterogeneous-hello-world/shader.cpp /multiple-definitions.hlsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 94d0147e6..c0d957b35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,8 +86,8 @@ auto_option( advanced_option(SLANG_ENABLE_DX_ON_VK "Use dxvk and vkd3d-proton for DirectX support" OFF) advanced_option(SLANG_ENABLE_SLANG_RHI "Use slang-rhi as dependency" ON) -option(SLANG_EMBED_STDLIB_SOURCE "Embed stdlib source in the binary" ON) -option(SLANG_EMBED_STDLIB "Build slang with an embedded version of the stdlib") +option(SLANG_EMBED_CORE_MODULE_SOURCE "Embed core module source in the binary" ON) +option(SLANG_EMBED_CORE_MODULE "Build slang with an embedded version of the core module") option(SLANG_ENABLE_FULL_IR_VALIDATION "Enable full IR validation (SLOW!)") option(SLANG_ENABLE_IR_BREAK_ALLOC, "Enable _debugUID on IR allocation") @@ -201,10 +201,10 @@ endif() # Option validation # -if(NOT SLANG_EMBED_STDLIB AND NOT SLANG_EMBED_STDLIB_SOURCE) +if(NOT SLANG_EMBED_CORE_MODULE AND NOT SLANG_EMBED_CORE_MODULE_SOURCE) message( SEND_ERROR - "One of SLANG_EMBED_STDLIB and SLANG_EMBED_STDLIB_SOURCE must be enabled" + "One of SLANG_EMBED_CORE_MODULE and SLANG_EMBED_CORE_MODULE_SOURCE must be enabled" ) endif() diff --git a/docs/building.md b/docs/building.md index ccc164ab1..a6bbd080d 100644 --- a/docs/building.md +++ b/docs/building.md @@ -125,8 +125,8 @@ See the [documentation on testing](../tools/slang-test/README.md) for more infor | Option | Default | Description | |-----------------------------------|----------------------------|----------------------------------------------------------------------------------------------| | `SLANG_VERSION` | Latest `v*` tag | The project version, detected using git if available | -| `SLANG_EMBED_STDLIB` | `FALSE` | Build slang with an embedded version of the stdlib | -| `SLANG_EMBED_STDLIB_SOURCE` | `TRUE` | Embed stdlib source in the binary | +| `SLANG_EMBED_CORE_MODULE` | `FALSE` | Build slang with an embedded version of the core module | +| `SLANG_EMBED_CORE_MODULE_SOURCE` | `TRUE` | Embed the core module source in the binary | | `SLANG_ENABLE_ASAN` | `FALSE` | Enable ASAN (address sanitizer) | | `SLANG_ENABLE_FULL_IR_VALIDATION` | `FALSE` | Enable full IR validation (SLOW!) | | `SLANG_ENABLE_IR_BREAK_ALLOC` | `FALSE` | Enable IR BreakAlloc functionality for debugging. | 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; - } -} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 8c2221a2b..26ab13909 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -56,7 +56,7 @@ generator( USE_FEWER_WARNINGS LINK_WITH_PRIVATE prelude - slang-without-embedded-stdlib + slang-without-embedded-core-module slang-capability-lookup slang-lookup-tables Threads::Threads diff --git a/tools/slang-test/parse-diagnostic-util.cpp b/tools/slang-test/parse-diagnostic-util.cpp index b0f13b4ee..f5b76a07e 100644 --- a/tools/slang-test/parse-diagnostic-util.cpp +++ b/tools/slang-test/parse-diagnostic-util.cpp @@ -449,17 +449,17 @@ static bool _isAtEnd(const UnownedStringSlice& text, const UnownedStringSlice& l SlangResult resB = ParseDiagnosticUtil::parseDiagnostics(b, diagsB); /* - TODO(JS): In the past we needed special handling of the stdlib, when - in some builds the path contains the stdlib. + TODO(JS): In the past we needed special handling of the core module, when + in some builds the path contains the core module. For now we don't seem to need this, this is for future reference, if there is an issue with needing to specially handle this. - static const UnownedStringSlice stdLibNames[] = + static const UnownedStringSlice coreModuleNames[] = { UnownedStringSlice::fromLiteral("core.meta.slang"), UnownedStringSlice::fromLiteral("hlsl.meta.slang"), - UnownedStringSlice::fromLiteral("slang-stdlib.cpp"), + UnownedStringSlice::fromLiteral("slang-core-module.cpp"), }; */ -- cgit v1.2.3