From d3ac3f86f3d5e4831cdfd6c374f2f0bb1ee30948 Mon Sep 17 00:00:00 2001 From: M Horga Date: Tue, 2 Jan 2024 19:03:10 -0600 Subject: [PATCH] Updated for Swift 5 and Metal 3 --- ch10/ch10new.playground/Contents.swift | 103 ++++++++++++++++++ .../Resources/Shaders.metal | 21 ++++ .../Sources/MetalView.swift | 48 ++++++++ ch10/ch10new.playground/contents.xcplayground | 4 + .../contents.xcworkspacedata | 7 ++ .../UserInterfaceState.xcuserstate | Bin 0 -> 37459 bytes .../UserInterfaceState.xcuserstate | Bin 0 -> 12369 bytes 7 files changed, 183 insertions(+) create mode 100644 ch10/ch10new.playground/Contents.swift create mode 100644 ch10/ch10new.playground/Resources/Shaders.metal create mode 100644 ch10/ch10new.playground/Sources/MetalView.swift create mode 100644 ch10/ch10new.playground/contents.xcplayground create mode 100644 ch10/ch10new.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 ch10/ch10new.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 ch10/ch10new.playground/playground.xcworkspace/xcuserdata/mhorga.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/ch10/ch10new.playground/Contents.swift b/ch10/ch10new.playground/Contents.swift new file mode 100644 index 0000000..9435df8 --- /dev/null +++ b/ch10/ch10new.playground/Contents.swift @@ -0,0 +1,103 @@ + +import MetalKit +import PlaygroundSupport + +guard let device = MTLCreateSystemDefaultDevice(), + let commandQueue = device.makeCommandQueue() else { + fatalError("Metal is not supported on this device") +} + +let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, + width: 600, + height: 600, + mipmapped: false) +textureDescriptor.usage = [.shaderWrite, .shaderRead] +guard let texture = device.makeTexture(descriptor: textureDescriptor) else { + fatalError("Failed to create texture") +} + +let shaderSource = """ +#include +using namespace metal; + +float dist(float2 point, float2 center, float radius) +{ + return length(point - center) - radius; +} + +kernel void compute(texture2d output [[texture(0)]], + uint2 gid [[thread_position_in_grid]]) +{ + int width = output.get_width(); + int height = output.get_height(); + float2 uv = float2(gid) / float2(width, height); + uv = uv * 2.0 - 1.0; + float distToCircle = dist(uv, float2(0), 0.5); + float distToCircle2 = dist(uv, float2(-0.1, 0.1), 0.5); + bool inside = distToCircle2 < 0; + output.write(inside ? float4(0) : float4(1, 0.7, 0, 1) * (1 - distToCircle), gid); +} +""" + +guard let library = try? device.makeLibrary(source: shaderSource, options: nil), + let kernelFunction = library.makeFunction(name: "compute"), + let computePipelineState = try? device.makeComputePipelineState(function: kernelFunction) else { + fatalError("Failed to create compute pipeline") +} + +guard let commandBuffer = commandQueue.makeCommandBuffer(), + let computeEncoder = commandBuffer.makeComputeCommandEncoder() else { + fatalError("Failed to create command buffer or compute encoder") +} + +let w = computePipelineState.threadExecutionWidth +let h = computePipelineState.maxTotalThreadsPerThreadgroup / w +let threadsPerThreadgroup = MTLSize(width: w, height: h, depth: 1) +let threadgroupsPerGrid = MTLSize(width: (texture.width + w - 1) / w, + height: (texture.height + h - 1) / h, + depth: 1) +computeEncoder.setComputePipelineState(computePipelineState) +computeEncoder.setTexture(texture, index: 0) +computeEncoder.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup) +computeEncoder.endEncoding() +commandBuffer.commit() +commandBuffer.waitUntilCompleted() + +class MetalView: MTKView { + var texture: MTLTexture! + + init(frame frameRect: CGRect, device: MTLDevice?, texture: MTLTexture?) { + self.texture = texture + super.init(frame: frameRect, device: device) + self.isPaused = true + self.enableSetNeedsDisplay = true + self.drawableSize = CGSize(width: 600, height: 600) // Set the drawable size here + } + + required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + override func draw(_ rect: CGRect) { + guard let drawable = self.currentDrawable else { return } + if drawable.texture.width != texture.width || drawable.texture.height != texture.height { + print("Drawable texture size does not match Metal texture size.") + return + } + guard let commandBuffer = device?.makeCommandQueue()?.makeCommandBuffer(), + let blitEncoder = commandBuffer.makeBlitCommandEncoder() else { return } + blitEncoder.copy(from: texture, + sourceSlice: 0, + sourceLevel: 0, + sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), + sourceSize: MTLSize(width: texture.width, height: texture.height, depth: 1), + to: drawable.texture, + destinationSlice: 0, + destinationLevel: 0, + destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0)) + blitEncoder.endEncoding() + commandBuffer.present(drawable) + commandBuffer.commit() + } +} + +let view = MetalView(frame: CGRect(x: 0, y: 0, width: 600, height: 600), device: device, texture: texture) +PlaygroundPage.current.liveView = view diff --git a/ch10/ch10new.playground/Resources/Shaders.metal b/ch10/ch10new.playground/Resources/Shaders.metal new file mode 100644 index 0000000..6a1f371 --- /dev/null +++ b/ch10/ch10new.playground/Resources/Shaders.metal @@ -0,0 +1,21 @@ + +#include +using namespace metal; + +float dist(float2 point, float2 center, float radius) +{ + return length(point - center) - radius; +} + +kernel void compute(texture2d output [[texture(0)]], + uint2 gid [[thread_position_in_grid]]) +{ + int width = output.get_width(); + int height = output.get_height(); + float2 uv = float2(gid) / float2(width, height); + uv = uv * 2.0 - 1.0; + float distToCircle = dist(uv, float2(0), 0.5); + float distToCircle2 = dist(uv, float2(-0.1, 0.1), 0.5); + bool inside = distToCircle2 < 0; + output.write(inside ? float4(0) : float4(1, 0.7, 0, 1) * (1 - distToCircle), gid); +} diff --git a/ch10/ch10new.playground/Sources/MetalView.swift b/ch10/ch10new.playground/Sources/MetalView.swift new file mode 100644 index 0000000..abd99e3 --- /dev/null +++ b/ch10/ch10new.playground/Sources/MetalView.swift @@ -0,0 +1,48 @@ + +import MetalKit + +public class MetalView: NSObject, MTKViewDelegate { + + public var device: MTLDevice! + var queue: MTLCommandQueue! + var cps: MTLComputePipelineState! + + override public init() { + super.init() + registerShaders() + } + + func registerShaders() { + device = MTLCreateSystemDefaultDevice()! + queue = device.makeCommandQueue() + guard let path = Bundle.main.path(forResource: "Shaders", ofType: "metal") else { + print("No shader file found") + return + } + do { + let input = try String(contentsOfFile: path, encoding: String.Encoding.utf8) + let library = try device.makeLibrary(source: input, options: nil) + let kernel = library.makeFunction(name: "compute")! + cps = try device.makeComputePipelineState(function: kernel) + } catch let e { + Swift.print("\(e)") + } + } + + public func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {} + + public func draw(in view: MTKView) { + if let drawable = view.currentDrawable, + let commandBuffer = queue.makeCommandBuffer(), + let commandEncoder = commandBuffer.makeComputeCommandEncoder() { + commandEncoder.setComputePipelineState(cps) + commandEncoder.setTexture(drawable.texture, index: 0) + let threadGroupCount = MTLSizeMake(8, 8, 1) + let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1) + commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) + commandEncoder.endEncoding() + commandBuffer.present(drawable) + commandBuffer.commit() + } + } +} diff --git a/ch10/ch10new.playground/contents.xcplayground b/ch10/ch10new.playground/contents.xcplayground new file mode 100644 index 0000000..06828af --- /dev/null +++ b/ch10/ch10new.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ch10/ch10new.playground/playground.xcworkspace/contents.xcworkspacedata b/ch10/ch10new.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ch10/ch10new.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ch10/ch10new.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate b/ch10/ch10new.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..f40c78edb1429e77bdcc848860a8cdbb3f7c38e0 GIT binary patch literal 37459 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 literal 0 HcmV?d00001