Skip to content

Commit b256285

Browse files
authored
Merge pull request #8 from yukiny0811/texture3d
3D Texture Support
2 parents f407bca + 3264b2f commit b256285

26 files changed

+960
-24
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1510"
4+
version = "1.7">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "56C015652B4D748600E51B4A"
18+
BuildableName = "ExampleiOS.app"
19+
BlueprintName = "ExampleiOS"
20+
ReferencedContainer = "container:ExampleiOS.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES"
30+
shouldAutocreateTestPlan = "YES">
31+
</TestAction>
32+
<LaunchAction
33+
buildConfiguration = "Debug"
34+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
35+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
36+
launchStyle = "0"
37+
useCustomWorkingDirectory = "NO"
38+
ignoresPersistentStateOnLaunch = "NO"
39+
debugDocumentVersioning = "YES"
40+
debugServiceExtension = "internal"
41+
allowLocationSimulation = "YES">
42+
<BuildableProductRunnable
43+
runnableDebuggingMode = "0">
44+
<BuildableReference
45+
BuildableIdentifier = "primary"
46+
BlueprintIdentifier = "56C015652B4D748600E51B4A"
47+
BuildableName = "ExampleiOS.app"
48+
BlueprintName = "ExampleiOS"
49+
ReferencedContainer = "container:ExampleiOS.xcodeproj">
50+
</BuildableReference>
51+
</BuildableProductRunnable>
52+
</LaunchAction>
53+
<ProfileAction
54+
buildConfiguration = "Release"
55+
shouldUseLaunchSchemeArgsEnv = "YES"
56+
savedToolIdentifier = ""
57+
useCustomWorkingDirectory = "NO"
58+
debugDocumentVersioning = "YES">
59+
<BuildableProductRunnable
60+
runnableDebuggingMode = "0">
61+
<BuildableReference
62+
BuildableIdentifier = "primary"
63+
BlueprintIdentifier = "56C015652B4D748600E51B4A"
64+
BuildableName = "ExampleiOS.app"
65+
BlueprintName = "ExampleiOS"
66+
ReferencedContainer = "container:ExampleiOS.xcodeproj">
67+
</BuildableReference>
68+
</BuildableProductRunnable>
69+
</ProfileAction>
70+
<AnalyzeAction
71+
buildConfiguration = "Debug">
72+
</AnalyzeAction>
73+
<ArchiveAction
74+
buildConfiguration = "Release"
75+
revealArchiveInOrganizer = "YES">
76+
</ArchiveAction>
77+
</Scheme>

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ class MyRender {
236236
- simd_float4x4
237237
- MTLTexture (only 2d texture)
238238

239+
### Supported Platforms
240+
- macOS 11.0~
241+
- iOS 14.0~
242+
- iOS Simulator (render shader only works on physical devices)
243+
239244
### Custom Pipelines
240245

241246
```.swift
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Yuki Kuwashima on 2024/01/12.
6+
//
7+
8+
import Foundation
9+
10+
@attached(
11+
extension,
12+
conformances: EMMetalComputeFunction,
13+
names: named(computePipelineState),
14+
named(args),
15+
named(init()),
16+
named(setup())
17+
)
18+
@attached(
19+
member,
20+
conformances: EMMetalComputeFunction,
21+
names: named(computePipelineState),
22+
named(args),
23+
named(init()),
24+
named(setup())
25+
)
26+
@attached(memberAttribute)
27+
public macro EMComputeShader3D() = #externalMacro(module: "EasyMetalShaderMacro", type: "EMComputeShader3D")

Sources/EasyMetalShader/Macros/EMTextureArgument.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
// Created by Yuki Kuwashima on 2024/01/12.
66
//
77

8+
import MetalKit
9+
810
@attached(accessor, names: named(didSet))
9-
public macro EMTextureArgument(_ usage: EMMetalTextureUsage) = #externalMacro(module: "EasyMetalShaderMacro", type: "EMTextureArgument")
11+
public macro EMTextureArgument(_ usage: EMMetalTextureUsage, _ type: MTLTextureType = .type2D) = #externalMacro(module: "EasyMetalShaderMacro", type: "EMTextureArgument")

Sources/EasyMetalShader/Models/EMMetalArgument.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ public enum EMMetalArgument {
2323
case float3x3(simd_float3x3)
2424
case float4x4(simd_float4x4)
2525
case texture2d(MTLTexture!, EMMetalTextureUsage)
26+
case texture3d(MTLTexture!, EMMetalTextureUsage)
2627

2728
}

Sources/EasyMetalShader/Models/EMMetalTexture.swift

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,74 @@ public class EMMetalTexture: NSObject {
1919
self.usage = usage
2020
}
2121

22-
public static func create(width: Int, height: Int, pixelFormat: MTLPixelFormat, label: String?) -> MTLTexture {
22+
public static func create(width: Int, height: Int, pixelFormat: MTLPixelFormat, label: String?, isRenderTarget: Bool = true) -> MTLTexture {
2323
let descriptor = MTLTextureDescriptor()
2424
descriptor.pixelFormat = pixelFormat
2525
descriptor.textureType = .type2D
2626
descriptor.width = width
2727
descriptor.height = height
28-
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
28+
if isRenderTarget {
29+
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
30+
} else {
31+
descriptor.usage = [.shaderRead, .shaderWrite]
32+
}
2933
descriptor.resourceOptions = .storageModePrivate
3034
let texture = ShaderCore.device.makeTexture(descriptor: descriptor)!
3135
texture.label = label
3236
return texture
3337
}
3438

35-
public static func createManaged(width: Int, height: Int, pixelFormat: MTLPixelFormat, label: String?) -> MTLTexture {
39+
public static func createManaged(width: Int, height: Int, pixelFormat: MTLPixelFormat, label: String?, isRenderTarget: Bool = true) -> MTLTexture {
3640
let descriptor = MTLTextureDescriptor()
3741
descriptor.pixelFormat = pixelFormat
3842
descriptor.textureType = .type2D
3943
descriptor.width = width
4044
descriptor.height = height
41-
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
45+
if isRenderTarget {
46+
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
47+
} else {
48+
descriptor.usage = [.shaderRead, .shaderWrite]
49+
}
50+
#if os(macOS)
51+
descriptor.resourceOptions = .storageModeManaged
52+
#elseif os(iOS)
53+
descriptor.resourceOptions = .storageModeShared
54+
#endif
55+
let texture = ShaderCore.device.makeTexture(descriptor: descriptor)!
56+
texture.label = label
57+
return texture
58+
}
59+
60+
public static func create3d(width: Int, height: Int, depth: Int, pixelFormat: MTLPixelFormat, label: String?, isRenderTarget: Bool = true) -> MTLTexture {
61+
let descriptor = MTLTextureDescriptor()
62+
descriptor.pixelFormat = pixelFormat
63+
descriptor.textureType = .type3D
64+
descriptor.width = width
65+
descriptor.height = height
66+
descriptor.depth = depth
67+
if isRenderTarget {
68+
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
69+
} else {
70+
descriptor.usage = [.shaderRead, .shaderWrite]
71+
}
72+
descriptor.resourceOptions = .storageModePrivate
73+
let texture = ShaderCore.device.makeTexture(descriptor: descriptor)!
74+
texture.label = label
75+
return texture
76+
}
77+
78+
public static func createManaged3d(width: Int, height: Int, depth: Int, pixelFormat: MTLPixelFormat, label: String?, isRenderTarget: Bool = true) -> MTLTexture {
79+
let descriptor = MTLTextureDescriptor()
80+
descriptor.pixelFormat = pixelFormat
81+
descriptor.textureType = .type3D
82+
descriptor.width = width
83+
descriptor.height = height
84+
descriptor.depth = depth
85+
if isRenderTarget {
86+
descriptor.usage = [.shaderRead, .shaderWrite, .renderTarget]
87+
} else {
88+
descriptor.usage = [.shaderRead, .shaderWrite]
89+
}
4290
#if os(macOS)
4391
descriptor.resourceOptions = .storageModeManaged
4492
#elseif os(iOS)

Sources/EasyMetalShader/Pipelines/EMMetalComputeFunction.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ extension EMMetalComputeFunction {
7474
encoder.setBytes([value], length: MemoryLayout<simd_float4x4>.stride, index: i+1)
7575
case .texture2d(let value, _):
7676
encoder.setTexture(value, index: i+1)
77+
case .texture3d(let value, _):
78+
encoder.setTexture(value, index: i+1)
7779
case .none:
7880
break
7981
}

Sources/EasyMetalShader/Pipelines/EMMetalRenderFunction.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ extension EMMetalRenderFunction {
7575
case .texture2d(let value, _):
7676
encoder.setVertexTexture(value, index: i+1)
7777
encoder.setFragmentTexture(value, index: i+1)
78+
case .texture3d(let value, _):
79+
encoder.setVertexTexture(value, index: i+1)
80+
encoder.setFragmentTexture(value, index: i+1)
7881
case .none:
7982
break
8083
}

Sources/EasyMetalShaderMacro/EMComputeShader/ComputeFunctionStrings/InitCompute.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99

1010
extension ComputeFunctionStrings {
11-
static func initFunc(variableInitStrings: [String]) -> String {
11+
static func initFunc(variableInitStrings: [String], gidTypeString: String) -> String {
1212
"""
1313
public func setup() {
1414
"""
@@ -61,12 +61,23 @@ public func setup() {
6161
case .sample:
6262
functionImpl += "texture2d<float, access::sample> \\(key) [[texture(\\(i+1))]]"
6363
}
64+
case .texture3d(_, let usage):
65+
switch usage {
66+
case .read:
67+
functionImpl += "texture3d<float, access::read> \\(key) [[texture(\\(i+1))]]"
68+
case .write:
69+
functionImpl += "texture3d<float, access::write> \\(key) [[texture(\\(i+1))]]"
70+
case .read_write:
71+
functionImpl += "texture3d<float, access::read_write> \\(key) [[texture(\\(i+1))]]"
72+
case .sample:
73+
functionImpl += "texture3d<float, access::sample> \\(key) [[texture(\\(i+1))]]"
74+
}
6475
case .none:
6576
break
6677
}
6778
functionImpl += ","
6879
}
69-
functionImpl += "ushort2 gid [[thread_position_in_grid]]"
80+
functionImpl += "\(gidTypeString) gid [[thread_position_in_grid]]"
7081
functionImpl += "){"
7182
7283
for key in args.keys {
@@ -97,6 +108,8 @@ public func setup() {
97108
functionImpl += "float4x4 \\(key) = \\(key)_buf[0];"
98109
case .texture2d(_, _):
99110
break
111+
case .texture3d(_, _):
112+
break
100113
case .none:
101114
break
102115
}

Sources/EasyMetalShaderMacro/EMComputeShader/EMComputeShader+MemberAttributeMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ extension EMComputeShader: MemberAttributeMacro {
6363
return [
6464
AttributeSyntax(
6565
attributeName: IdentifierTypeSyntax(
66-
name: .identifier("EMTextureArgument(.read_write)")
66+
name: .identifier("EMTextureArgument(.read_write, .type2D)")
6767
)
6868
)
6969
]

Sources/EasyMetalShaderMacro/EMComputeShader/EMComputeShader+MemberMacro.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,28 @@ extension EMComputeShader: MemberMacro {
5656
if let type = binding.typeAnnotation?.type {
5757
if type.trimmedDescription == "MTLTexture?" {
5858
var usage: String? = nil
59+
var format: String? = nil
5960
for element in variableDecl.attributes {
6061
if let attribute = element.as(AttributeSyntax.self) {
6162
if attribute.attributeName.trimmedDescription == "EMTextureArgument" {
62-
if let args = attribute.arguments {
63-
usage = args.trimmedDescription
63+
if let args = attribute.arguments?.as(LabeledExprListSyntax.self) {
64+
usage = args.first?.as(LabeledExprSyntax.self)?.expression.as(MemberAccessExprSyntax.self)?.declName.baseName.trimmedDescription
65+
if args.count >= 2 {
66+
format = args[args.index(args.startIndex, offsetBy: 1)].as(LabeledExprSyntax.self)?.expression.as(
67+
MemberAccessExprSyntax.self
68+
)?.declName.baseName.trimmedDescription
69+
}
6470
}
71+
6572
}
6673
}
6774
}
6875
if let usage {
69-
if let setString = Util.textureTypeToArgumentString(textureType: type.trimmedDescription, variableName: variableName, usage: usage) {
76+
if let setString = Util.textureTypeToArgumentString(textureType: type.trimmedDescription, variableName: variableName, usage: usage, format: format) {
7077
initStringList.append("args[\"\(variableName)\"] = \(setString)")
7178
}
7279
} else {
73-
if let setString = Util.textureTypeToArgumentString(textureType: type.trimmedDescription, variableName: variableName, usage: ".read_write") {
80+
if let setString = Util.textureTypeToArgumentString(textureType: type.trimmedDescription, variableName: variableName, usage: "read_write", format: format) {
7481
initStringList.append("args[\"\(variableName)\"] = \(setString)")
7582
}
7683
}
@@ -126,7 +133,7 @@ extension EMComputeShader: MemberMacro {
126133
var args: [String: EMMetalArgument] = [:]
127134
"""
128135

129-
let thisDecl3: DeclSyntax = .init(stringLiteral: ComputeFunctionStrings.initFunc(variableInitStrings: initStringList))
136+
let thisDecl3: DeclSyntax = .init(stringLiteral: ComputeFunctionStrings.initFunc(variableInitStrings: initStringList, gidTypeString: "ushort2"))
130137

131138

132139
var thisDecl4: DeclSyntax = ""
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Yuki Kuwashima on 2024/01/12.
6+
//
7+
8+
import Foundation
9+
10+
enum ComputeFunctionStrings3D {}

0 commit comments

Comments
 (0)