Skip to content

Commit 48e567b

Browse files
authored
Merge branch 'master' into bindless
2 parents 4a6b7ae + cbdc7e1 commit 48e567b

29 files changed

+705
-162
lines changed

docs/cuda-target.md

+11
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,17 @@ There is potential to calculate the lane id using the [numthreads] markup in Sla
301301
* Intrinsics which only work in pixel shaders
302302
+ QuadXXXX intrinsics
303303

304+
OptiX Support
305+
=============
306+
307+
Slang supports OptiX for raytracing. To compile raytracing programs, NVRTC must have access to the `optix.h` and dependent files that are typically distributed as part of the OptiX SDK. When Slang detects the use of raytracing in source, it will define `SLANG_CUDA_ENABLE_OPTIX` when `slang-cuda-prelude.h` is included. This will in turn try to include `optix.h`.
308+
309+
Slang tries several mechanisms to locate `optix.h` when NVRTC is initiated. The first mechanism is to look in the include paths that are passed to Slang. If `optix.h` can be found in one of these paths, no more searching will be performed.
310+
311+
If this fails, the default OptiX SDK install locations are searched. On Windows this is `%{PROGRAMDATA}\NVIDIA Corporation\OptiX SDK X.X.X\include`. On Linux this is `${HOME}/NVIDIA-OptiX-SDK-X.X.X-suffix`.
312+
313+
If OptiX headers cannot be found, compilation will fail.
314+
304315
Limitations
305316
===========
306317

docs/user-guide/03-convenience-features.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ int rs = foo.staticMethod(a,b);
149149

150150
### Mutability of member function
151151

152-
For GPU performance considerations, the `this` argument in a member function is immutable by default. If you modify the content in `this` argument, the modification will be discarded after the call and does not affect the input object. If you intend to define a member function that mutates the object, use `[mutating]` attribute on the member function as shown in the following example.
152+
For GPU performance considerations, the `this` argument in a member function is immutable by default. Attempting to modify `this` will result in a compile error. If you intend to define a member function that mutates the object, use `[mutating]` attribute on the member function as shown in the following example.
153153

154154
```hlsl
155155
struct Foo
@@ -159,14 +159,14 @@ struct Foo
159159
[mutating]
160160
void setCount(int x) { count = x; }
161161
162-
void setCount2(int x) { count = x; }
162+
// This would fail to compile.
163+
// void setCount2(int x) { count = x; }
163164
}
164165
165166
void test()
166167
{
167168
Foo f;
168-
f.setCount(1); // f.count is 1 after the call.
169-
f.setCount2(2); // f.count is still 1 after the call.
169+
f.setCount(1); // Compiles
170170
}
171171
```
172172

source/compiler-core/slang-nvrtc-compiler.cpp

+195-62
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,14 @@ class NVRTCDownstreamCompiler : public DownstreamCompilerBase
127127
nvrtcProgram m_program;
128128
};
129129

130-
SlangResult _findIncludePath(String& outIncludePath);
130+
SlangResult _findCUDAIncludePath(String& outIncludePath);
131+
SlangResult _getCUDAIncludePath(String& outIncludePath);
131132

132-
SlangResult _getIncludePath(String& outIncludePath);
133+
SlangResult _findOptixIncludePath(String& outIncludePath);
134+
SlangResult _getOptixIncludePath(String& outIncludePath);
133135

134136
SlangResult _maybeAddHalfSupport(const CompileOptions& options, CommandLine& ioCmdLine);
137+
SlangResult _maybeAddOptixSupport(const CompileOptions& options, CommandLine& ioCmdLine);
135138

136139
#define SLANG_NVTRC_MEMBER_FUNCS(ret, name, params) ret(*m_##name) params;
137140

@@ -140,9 +143,16 @@ class NVRTCDownstreamCompiler : public DownstreamCompilerBase
140143
// Holds list of paths passed in where cuda_fp16.h is found. Does *NOT* include cuda_fp16.h.
141144
List<String> m_cudaFp16FoundPaths;
142145

143-
bool m_includeSearched = false;
146+
bool m_cudaIncludeSearched = false;
144147
// Holds location of where include (for cuda_fp16.h) is found.
145-
String m_includePath;
148+
String m_cudaIncludePath;
149+
150+
// Holds list of paths passed in where optix.h is found. Does *NOT* include optix.h.
151+
List<String> m_optixFoundPaths;
152+
153+
bool m_optixIncludeSearched = false;
154+
// Holds location of where include (for optix.h) is found.
155+
String m_optixIncludePath;
146156

147157
ComPtr<ISlangSharedLibrary> m_sharedLibrary;
148158
};
@@ -602,21 +612,8 @@ static SlangResult _findNVRTC(NVRTCPathVisitor& visitor)
602612
}
603613

604614
static const UnownedStringSlice g_fp16HeaderName = UnownedStringSlice::fromLiteral("cuda_fp16.h");
615+
static const UnownedStringSlice g_optixHeaderName = UnownedStringSlice::fromLiteral("optix.h");
605616

606-
SlangResult NVRTCDownstreamCompiler::_getIncludePath(String& outPath)
607-
{
608-
if (!m_includeSearched)
609-
{
610-
m_includeSearched = true;
611-
612-
SLANG_ASSERT(m_includePath.getLength() == 0);
613-
614-
_findIncludePath(m_includePath);
615-
}
616-
617-
outPath = m_includePath;
618-
return m_includePath.getLength() ? SLANG_OK : SLANG_E_NOT_FOUND;
619-
}
620617

621618
SlangResult _findFileInIncludePath(
622619
const String& path,
@@ -650,7 +647,7 @@ SlangResult _findFileInIncludePath(
650647
return SLANG_E_NOT_FOUND;
651648
}
652649

653-
SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath)
650+
SlangResult NVRTCDownstreamCompiler::_findCUDAIncludePath(String& outPath)
654651
{
655652
outPath = String();
656653

@@ -711,6 +708,130 @@ SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath)
711708
return SLANG_E_NOT_FOUND;
712709
}
713710

711+
SlangResult NVRTCDownstreamCompiler::_getCUDAIncludePath(String& outPath)
712+
{
713+
if (!m_cudaIncludeSearched)
714+
{
715+
m_cudaIncludeSearched = true;
716+
717+
SLANG_ASSERT(m_cudaIncludePath.getLength() == 0);
718+
719+
_findCUDAIncludePath(m_cudaIncludePath);
720+
}
721+
722+
outPath = m_cudaIncludePath;
723+
return m_cudaIncludePath.getLength() ? SLANG_OK : SLANG_E_NOT_FOUND;
724+
}
725+
726+
SlangResult NVRTCDownstreamCompiler::_findOptixIncludePath(String& outPath)
727+
{
728+
outPath = String();
729+
730+
List<String> rootPaths;
731+
732+
#if SLANG_WINDOWS_FAMILY
733+
const char* searchPattern = "OptiX SDK *";
734+
StringBuilder builder;
735+
if (SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable(
736+
UnownedStringSlice::fromLiteral("PROGRAMDATA"),
737+
builder)))
738+
{
739+
rootPaths.add(Path::combine(builder, "NVIDIA Corporation"));
740+
}
741+
#else
742+
const char* searchPattern = "NVIDIA-OptiX-SDK-*";
743+
StringBuilder builder;
744+
if (SLANG_SUCCEEDED(
745+
PlatformUtil::getEnvironmentVariable(UnownedStringSlice::fromLiteral("HOME"), builder)))
746+
{
747+
rootPaths.add(builder);
748+
}
749+
#endif
750+
751+
struct OptixHeaders
752+
{
753+
String path;
754+
SemanticVersion version;
755+
};
756+
757+
// Visitor to find Optix headers.
758+
struct Visitor : public Path::Visitor
759+
{
760+
const String& rootPath;
761+
List<OptixHeaders>& optixPaths;
762+
Visitor(const String& rootPath, List<OptixHeaders>& optixPaths)
763+
: rootPath(rootPath), optixPaths(optixPaths)
764+
{
765+
}
766+
void accept(Path::Type type, const UnownedStringSlice& path) SLANG_OVERRIDE
767+
{
768+
if (type != Path::Type::Directory)
769+
return;
770+
771+
OptixHeaders optixPath;
772+
#if SLANG_WINDOWS_FAMILY
773+
// Paths are expected to look like ".\OptiX SDK X.X.X"
774+
auto versionString = path.subString(path.lastIndexOf(' ') + 1, path.getLength());
775+
#else
776+
// Paths are expected to look like "./NVIDIA-OptiX-SDK-X.X.X-suffix"
777+
auto versionString = path.subString(0, path.lastIndexOf('-'));
778+
versionString =
779+
versionString.subString(path.lastIndexOf('-') + 1, versionString.getLength());
780+
#endif
781+
if (SLANG_SUCCEEDED(SemanticVersion::parse(versionString, '.', optixPath.version)))
782+
{
783+
optixPath.path = Path::combine(Path::combine(rootPath, path), "include");
784+
String optixHeader = Path::combine(optixPath.path, g_optixHeaderName);
785+
if (File::exists(optixHeader))
786+
{
787+
optixPaths.add(optixPath);
788+
}
789+
}
790+
}
791+
};
792+
793+
List<OptixHeaders> optixPaths;
794+
795+
for (const String& rootPath : rootPaths)
796+
{
797+
Visitor visitor(rootPath, optixPaths);
798+
Path::find(rootPath, searchPattern, &visitor);
799+
}
800+
801+
// Find newest version
802+
const OptixHeaders* newest = nullptr;
803+
for (Index i = 0; i < optixPaths.getCount(); ++i)
804+
{
805+
if (!newest || optixPaths[i].version > newest->version)
806+
{
807+
newest = &optixPaths[i];
808+
}
809+
}
810+
811+
if (newest)
812+
{
813+
outPath = newest->path;
814+
return SLANG_OK;
815+
}
816+
817+
return SLANG_E_NOT_FOUND;
818+
}
819+
820+
SlangResult NVRTCDownstreamCompiler::_getOptixIncludePath(String& outPath)
821+
{
822+
if (!m_optixIncludeSearched)
823+
{
824+
m_optixIncludeSearched = true;
825+
826+
SLANG_ASSERT(m_optixIncludePath.getLength() == 0);
827+
828+
_findOptixIncludePath(m_optixIncludePath);
829+
}
830+
831+
outPath = m_optixIncludePath;
832+
return m_optixIncludePath.getLength() ? SLANG_OK : SLANG_E_NOT_FOUND;
833+
}
834+
714835
SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(
715836
const DownstreamCompileOptions& options,
716837
CommandLine& ioCmdLine)
@@ -747,7 +868,7 @@ SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(
747868
}
748869

749870
String includePath;
750-
SLANG_RETURN_ON_FAIL(_getIncludePath(includePath));
871+
SLANG_RETURN_ON_FAIL(_getCUDAIncludePath(includePath));
751872

752873
// Add the found include path
753874
ioCmdLine.addArg("-I");
@@ -758,6 +879,48 @@ SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(
758879
return SLANG_OK;
759880
}
760881

882+
SlangResult NVRTCDownstreamCompiler::_maybeAddOptixSupport(
883+
const DownstreamCompileOptions& options,
884+
CommandLine& ioCmdLine)
885+
{
886+
// First check if we know if one of the include paths contains optix.h
887+
for (const auto& includePath : options.includePaths)
888+
{
889+
if (m_optixFoundPaths.indexOf(includePath) >= 0)
890+
{
891+
// Okay we have an include path that we know works.
892+
// Just need to enable OptiX in prelude
893+
ioCmdLine.addArg("-DSLANG_CUDA_ENABLE_OPTIX");
894+
return SLANG_OK;
895+
}
896+
}
897+
898+
// Let's see if one of the paths finds optix.h
899+
for (const auto& curIncludePath : options.includePaths)
900+
{
901+
const String includePath = asString(curIncludePath);
902+
const String checkPath = Path::combine(includePath, g_optixHeaderName);
903+
if (File::exists(checkPath))
904+
{
905+
m_optixFoundPaths.add(includePath);
906+
// Just need to enable OptiX in prelude
907+
ioCmdLine.addArg("-DSLANG_CUDA_ENABLE_OPTIX");
908+
return SLANG_OK;
909+
}
910+
}
911+
912+
String includePath;
913+
SLANG_RETURN_ON_FAIL(_getOptixIncludePath(includePath));
914+
915+
// Add the found include path
916+
ioCmdLine.addArg("-I");
917+
ioCmdLine.addArg(includePath);
918+
919+
ioCmdLine.addArg("-DSLANG_CUDA_ENABLE_OPTIX");
920+
921+
return SLANG_OK;
922+
}
923+
761924
SlangResult NVRTCDownstreamCompiler::compile(
762925
const DownstreamCompileOptions& inOptions,
763926
IArtifact** outArtifact)
@@ -780,6 +943,9 @@ SlangResult NVRTCDownstreamCompiler::compile(
780943

781944
CommandLine cmdLine;
782945

946+
// --dopt option is only available in CUDA 11.7 and later
947+
bool hasDoptOption = m_desc.version >= SemanticVersion(11, 7);
948+
783949
switch (options.debugInfoType)
784950
{
785951
case DebugInfoType::None:
@@ -789,12 +955,20 @@ SlangResult NVRTCDownstreamCompiler::compile(
789955
default:
790956
{
791957
cmdLine.addArg("--device-debug");
958+
if (hasDoptOption)
959+
{
960+
cmdLine.addArg("--dopt=on");
961+
}
792962
break;
793963
}
794964
case DebugInfoType::Maximal:
795965
{
796966
cmdLine.addArg("--device-debug");
797967
cmdLine.addArg("--generate-line-info");
968+
if (hasDoptOption)
969+
{
970+
cmdLine.addArg("--dopt=on");
971+
}
798972
break;
799973
}
800974
}
@@ -910,48 +1084,7 @@ SlangResult NVRTCDownstreamCompiler::compile(
9101084
//
9111085
if (options.pipelineType == PipelineType::RayTracing)
9121086
{
913-
// The device-side OptiX API is accessed through a constellation
914-
// of headers provided by the OptiX SDK, so we need to set an
915-
// include path for the compile that makes those visible.
916-
//
917-
// TODO: The OptiX SDK installer doesn't set any kind of environment
918-
// variable to indicate where the SDK was installed, so we seemingly
919-
// need to probe paths instead. The form of the path will differ
920-
// betwene Windows and Unix-y platforms, and we will need some kind
921-
// of approach to probe multiple versiosn and use the latest.
922-
//
923-
// HACK: For now I'm using the fixed path for the most recent SDK
924-
// release on Windows. This means that OptiX cross-compilation will
925-
// only "work" on a subset of platforms, but that doesn't matter
926-
// for now since it doesn't really "work" at all.
927-
//
928-
cmdLine.addArg("-I");
929-
cmdLine.addArg("C:/ProgramData/NVIDIA Corporation/OptiX SDK 7.0.0/include/");
930-
931-
// The OptiX headers in turn `#include <stddef.h>` and expect that
932-
// to work. We could try to also add in an include path from the CUDA
933-
// SDK (which seems to provide a `stddef.h` in the most recent version),
934-
// but using that version doesn't seem to work (and also bakes in a
935-
// requirement that the user have the CUDA SDK installed in addition
936-
// to the OptiX SDK).
937-
//
938-
// Instead, we will rely on the NVRTC feature that lets us set up
939-
// memory buffers to be used as include files by the we compile.
940-
// We will define a dummy `stddef.h` that includes the bare minimum
941-
// lines required to get the OptiX headers to compile without complaint.
942-
//
943-
// TODO: Confirm that the `LP64` definition here is actually needed.
944-
//
945-
headerIncludeNames.add("stddef.h");
946-
headers.add("#pragma once\n"
947-
"#define LP64\n");
948-
949-
// Finally, we want the CUDA prelude to be able to react to whether
950-
// or not OptiX is required (most notably by `#include`ing the appropriate
951-
// header(s)), so we will insert a preprocessor define to indicate
952-
// the requirement.
953-
//
954-
cmdLine.addArg("-DSLANG_CUDA_ENABLE_OPTIX");
1087+
SLANG_RETURN_ON_FAIL(_maybeAddOptixSupport(options, cmdLine));
9551088
}
9561089

9571090
// Add any compiler specific options

0 commit comments

Comments
 (0)