Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Select Xcode 16.2
run: sudo xcode-select -s /Applications/Xcode_16.2.app
- name: Select Xcode 16.4
run: sudo xcode-select -s /Applications/Xcode_16.4.app

- name: Show Xcode version
run: xcodebuild -version
Expand Down
7 changes: 7 additions & 0 deletions Sources/SwiftSlang/SLGlobalSession.mm
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ - (nullable SLSession *)createSessionWithDesc:(SLSessionDesc *)desc
// Build search paths
std::vector<const char *> searchPaths;
std::vector<std::string> searchPathStrings; // Keep strings alive
NSUInteger searchPathCount = desc.searchPaths.count;
searchPathStrings.reserve(searchPathCount);
searchPaths.reserve(searchPathCount);
for (NSString *path in desc.searchPaths) {
searchPathStrings.push_back([path UTF8String]);
searchPaths.push_back(searchPathStrings.back().c_str());
Expand All @@ -74,6 +77,10 @@ - (nullable SLSession *)createSessionWithDesc:(SLSessionDesc *)desc
std::vector<slang::PreprocessorMacroDesc> macros;
std::vector<std::string> macroNames;
std::vector<std::string> macroValues;
NSUInteger macroCount = desc.preprocessorMacros.count;
macroNames.reserve(macroCount);
macroValues.reserve(macroCount);
macros.reserve(macroCount);
for (NSString *name in desc.preprocessorMacros) {
NSString *value = desc.preprocessorMacros[name];
macroNames.push_back([name UTF8String]);
Expand Down
104 changes: 104 additions & 0 deletions Tests/SwiftSlangTests/SwiftSlangTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,110 @@ final class SwiftSlangTests: XCTestCase {
XCTAssertEqual(texType.getResourceAccess(), .read)
}

// MARK: - Preprocessor Macros

func testPreprocessorMacroAffectsCompilation() throws {
let globalSession = try SLGlobalSession.create()
let profile = globalSession.findProfile("sm_5_0")
let targetDesc = SLTargetDesc(format: .metal, profile: profile)

let source = """
uniform float intensity;
[shader("fragment")]
float4 fragMain() : SV_Target {
#ifdef USE_RED
return float4(intensity, 0, 0, 1);
#else
return float4(0, 0, intensity, 1);
#endif
}
"""

// With USE_RED defined
let sessionDescWithMacro = SLSessionDesc()
sessionDescWithMacro.targets = [targetDesc]
sessionDescWithMacro.preprocessorMacros = ["USE_RED": "1"]
let sessionWith = try globalSession.createSession(with: sessionDescWithMacro)
let moduleWith = try sessionWith.loadModule(fromSourceString: "Test", path: "<inline>", source: source)
let epWith = try moduleWith.entryPoint(at: 0)
let compositeWith = try sessionWith.createCompositeComponentType(with: moduleWith, entryPoints: [epWith])
let linkedWith = try compositeWith.link()
let codeWith = try linkedWith.getTargetCode(0)

// Without USE_RED defined
let sessionDescWithout = SLSessionDesc()
sessionDescWithout.targets = [targetDesc]
let sessionWithout = try globalSession.createSession(with: sessionDescWithout)
let moduleWithout = try sessionWithout.loadModule(fromSourceString: "Test", path: "<inline>", source: source)
let epWithout = try moduleWithout.entryPoint(at: 0)
let compositeWithout = try sessionWithout.createCompositeComponentType(with: moduleWithout, entryPoints: [epWithout])
let linkedWithout = try compositeWithout.link()
let codeWithout = try linkedWithout.getTargetCode(0)

// Both should compile successfully but produce different Metal code
XCTAssertGreaterThan(codeWith.count, 0)
XCTAssertGreaterThan(codeWithout.count, 0)
XCTAssertNotEqual(codeWith, codeWithout)
}

func testMultiplePreprocessorMacros() throws {
let globalSession = try SLGlobalSession.create()
let profile = globalSession.findProfile("sm_5_0")
let targetDesc = SLTargetDesc(format: .metal, profile: profile)
let sessionDesc = SLSessionDesc()
sessionDesc.targets = [targetDesc]
sessionDesc.preprocessorMacros = [
"RESOLUTION_X": "1920",
"RESOLUTION_Y": "1080",
"SCALE": "2",
]
let session = try globalSession.createSession(with: sessionDesc)

let source = """
[shader("fragment")]
float4 fragMain() : SV_Target {
float x = RESOLUTION_X;
float y = RESOLUTION_Y;
float s = SCALE;
return float4(x, y, s, 1);
}
"""
let module = try session.loadModule(fromSourceString: "Test", path: "<inline>", source: source)
let entryPoint = try module.entryPoint(at: 0)
let composite = try session.createCompositeComponentType(with: module, entryPoints: [entryPoint])
let linked = try composite.link()
let metalCode = try linked.getTargetCode(0)
XCTAssertGreaterThan(metalCode.count, 0)
}

func testPreprocessorMacroWithValue() throws {
let globalSession = try SLGlobalSession.create()
let profile = globalSession.findProfile("sm_5_0")
let targetDesc = SLTargetDesc(format: .metal, profile: profile)
let sessionDesc = SLSessionDesc()
sessionDesc.targets = [targetDesc]
sessionDesc.preprocessorMacros = ["CHANNEL_COUNT": "3"]
let session = try globalSession.createSession(with: sessionDesc)

let source = """
uniform float values[CHANNEL_COUNT];
[shader("fragment")]
float4 fragMain() : SV_Target { return float4(values[0], values[1], values[2], 1); }
"""
let module = try session.loadModule(fromSourceString: "Test", path: "<inline>", source: source)
let entryPoint = try module.entryPoint(at: 0)
let composite = try session.createCompositeComponentType(with: module, entryPoints: [entryPoint])
let linked = try composite.link()
let params = try linked.getShaderParameters(0)

let valuesParam = params.first { $0.name == "values" }
XCTAssertNotNil(valuesParam)
let typeLayout = try XCTUnwrap(valuesParam?.typeLayout)
let type = try XCTUnwrap(typeLayout.getType())
XCTAssertEqual(type.getKind(), .array)
XCTAssertEqual(type.getElementCount(), 3)
}

// MARK: - Entry Point

func testComputeEntryPoint() throws {
Expand Down
Loading