From aa819fcdc9332ee7330d049955a3f88b94e5f47d Mon Sep 17 00:00:00 2001 From: dscyrescotti Date: Wed, 22 May 2024 22:59:48 +0700 Subject: [PATCH 1/3] feat: use indexed rendering --- Memola/Canvas/Geometries/Stroke/Stroke.swift | 16 +++++++++---- .../RenderPasses/EraserRenderPass.swift | 7 ++++-- .../RenderPasses/StrokeRenderPass.swift | 7 ++++-- Memola/Canvas/Shaders/Quad.metal | 23 ++++++++++++------- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/Memola/Canvas/Geometries/Stroke/Stroke.swift b/Memola/Canvas/Geometries/Stroke/Stroke.swift index 32081b2..8018da1 100644 --- a/Memola/Canvas/Geometries/Stroke/Stroke.swift +++ b/Memola/Canvas/Geometries/Stroke/Stroke.swift @@ -56,8 +56,9 @@ final class Stroke: @unchecked Sendable { let movingAverage = MovingAverage(windowSize: 3) - var vertexBuffer: MTLBuffer? var texture: MTLTexture? + var indexBuffer: MTLBuffer? + var vertexBuffer: MTLBuffer? var isEmpty: Bool { quads.isEmpty @@ -160,12 +161,19 @@ extension Stroke: Drawable { } func draw(device: MTLDevice, renderEncoder: MTLRenderCommandEncoder) { - guard !isEmpty else { return } + guard !isEmpty, let indexBuffer else { return } prepare(device: device) renderEncoder.setFragmentTexture(texture, index: 0) renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0) - renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: quads.endIndex * 6) - vertexBuffer = nil + renderEncoder.drawIndexedPrimitives( + type: .triangle, + indexCount: quads.endIndex * 6, + indexType: .uint32, + indexBuffer: indexBuffer, + indexBufferOffset: 0 + ) + self.vertexBuffer = nil + self.indexBuffer = nil } } diff --git a/Memola/Canvas/RenderPasses/EraserRenderPass.swift b/Memola/Canvas/RenderPasses/EraserRenderPass.swift index 46bbe54..32f115d 100644 --- a/Memola/Canvas/RenderPasses/EraserRenderPass.swift +++ b/Memola/Canvas/RenderPasses/EraserRenderPass.swift @@ -57,12 +57,15 @@ class EraserRenderPass: RenderPass { let quadCount = stroke.quads.endIndex var quads = stroke.quads let quadBuffer = renderer.device.makeBuffer(bytes: &quads, length: MemoryLayout.stride * quadCount, options: []) - let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 4, options: []) computeEncoder.setComputePipelineState(quadPipelineState) computeEncoder.setBuffer(quadBuffer, offset: 0, index: 0) - computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 1) + computeEncoder.setBuffer(indexBuffer, offset: 0, index: 1) + computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 2) + stroke.indexBuffer = indexBuffer stroke.vertexBuffer = vertexBuffer let threadsPerGroup = MTLSize(width: 1, height: 1, depth: 1) diff --git a/Memola/Canvas/RenderPasses/StrokeRenderPass.swift b/Memola/Canvas/RenderPasses/StrokeRenderPass.swift index c268735..89945af 100644 --- a/Memola/Canvas/RenderPasses/StrokeRenderPass.swift +++ b/Memola/Canvas/RenderPasses/StrokeRenderPass.swift @@ -70,12 +70,15 @@ class StrokeRenderPass: RenderPass { let quadCount = stroke.quads.endIndex var quads = stroke.quads let quadBuffer = renderer.device.makeBuffer(bytes: &quads, length: MemoryLayout.stride * quadCount, options: []) - let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 4, options: []) computeEncoder.setComputePipelineState(quadPipelineState) computeEncoder.setBuffer(quadBuffer, offset: 0, index: 0) - computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 1) + computeEncoder.setBuffer(indexBuffer, offset: 0, index: 1) + computeEncoder.setBuffer(vertexBuffer, offset: 0, index: 2) + stroke.indexBuffer = indexBuffer stroke.vertexBuffer = vertexBuffer let threadsPerGroup = MTLSize(width: 1, height: 1, depth: 1) diff --git a/Memola/Canvas/Shaders/Quad.metal b/Memola/Canvas/Shaders/Quad.metal index 8bd9cc8..898c3d0 100644 --- a/Memola/Canvas/Shaders/Quad.metal +++ b/Memola/Canvas/Shaders/Quad.metal @@ -39,16 +39,23 @@ Vertex createVertex(Quad quad, float2 factor, float2 textCoord) { kernel void generate_stroke_vertices( device Quad *quads [[buffer(0)]], - device Vertex *vertices [[buffer(1)]], + device uint *indices [[buffer(1)]], + device Vertex *vertices [[buffer(2)]], uint gid [[thread_position_in_grid]] ) { - uint index = gid * 6; Quad quad = quads[gid]; + uint index = gid * 6; + uint vertexIndex = gid * 4; float halfSize = quad.size * 0.5; - vertices[index] = createVertex(quad, float2(-halfSize, -halfSize), float2(0, 0)); - vertices[index + 1] = createVertex(quad, float2(halfSize, -halfSize), float2(1, 0)); - vertices[index + 2] = createVertex(quad, float2(-halfSize, halfSize), float2(0, 1)); - vertices[index + 3] = createVertex(quad, float2(halfSize, -halfSize), float2(1, 0)); - vertices[index + 4] = createVertex(quad, float2(-halfSize, halfSize), float2(0, 1)); - vertices[index + 5] = createVertex(quad, float2(halfSize, halfSize), float2(1, 1)); + vertices[vertexIndex] = createVertex(quad, float2(-halfSize, -halfSize), float2(0, 0)); + vertices[vertexIndex + 1] = createVertex(quad, float2(halfSize, -halfSize), float2(1, 0)); + vertices[vertexIndex + 2] = createVertex(quad, float2(-halfSize, halfSize), float2(0, 1)); + vertices[vertexIndex + 3] = createVertex(quad, float2(halfSize, halfSize), float2(1, 1)); + + indices[index] = vertexIndex; + indices[index + 1] = vertexIndex + 1; + indices[index + 2] = vertexIndex + 2; + indices[index + 3] = vertexIndex + 1; + indices[index + 4] = vertexIndex + 2; + indices[index + 5] = vertexIndex + 3; } From 24a9c3ed5139d3514c5cfb7e0861eb51ed7e1bb8 Mon Sep 17 00:00:00 2001 From: dscyrescotti Date: Wed, 22 May 2024 23:31:21 +0700 Subject: [PATCH 2/3] feat: update pen thicknesses --- Memola/Canvas/Tool/Pen/PenStyles/EraserPenStyle.swift | 6 +++--- Memola/Canvas/Tool/Pen/PenStyles/MarkerPenStyle.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Memola/Canvas/Tool/Pen/PenStyles/EraserPenStyle.swift b/Memola/Canvas/Tool/Pen/PenStyles/EraserPenStyle.swift index 930b1c7..c8cecc2 100644 --- a/Memola/Canvas/Tool/Pen/PenStyles/EraserPenStyle.swift +++ b/Memola/Canvas/Tool/Pen/PenStyles/EraserPenStyle.swift @@ -11,10 +11,10 @@ struct EraserPenStyle: PenStyle { var icon: (base: String, tip: String?) = ("eraser", nil) var textureName: String = "point-texture" + + var thickness: (min: CGFloat, max: CGFloat) = (0.5, 30) - var thickness: (min: CGFloat, max: CGFloat) = (0.5, 40) - - var thicknessSteps: [CGFloat] = [0.5, 1, 2, 5, 7.5, 10, 15, 20, 25, 30, 35, 40] + var thicknessSteps: [CGFloat] = [0.5, 1, 2, 5, 7.5, 10, 12.5, 15, 17.5, 20, 25, 30] var color: [CGFloat] = [1, 1, 1, 0] diff --git a/Memola/Canvas/Tool/Pen/PenStyles/MarkerPenStyle.swift b/Memola/Canvas/Tool/Pen/PenStyles/MarkerPenStyle.swift index 9c25a7b..cc7acd0 100644 --- a/Memola/Canvas/Tool/Pen/PenStyles/MarkerPenStyle.swift +++ b/Memola/Canvas/Tool/Pen/PenStyles/MarkerPenStyle.swift @@ -12,9 +12,9 @@ struct MarkerPenStyle: PenStyle { var textureName: String = "point-texture" - var thickness: (min: CGFloat, max: CGFloat) = (0.5, 40) + var thickness: (min: CGFloat, max: CGFloat) = (0.5, 30) - var thicknessSteps: [CGFloat] = [0.5, 1, 2, 5, 7.5, 10, 15, 20, 25, 30, 35, 40] + var thicknessSteps: [CGFloat] = [0.5, 1, 2, 5, 7.5, 10, 12.5, 15, 17.5, 20, 25, 30] var color: [CGFloat] = [1, 0.38, 0.38, 1] From 81fb43f3e328bbb65ffb88706f7bc03d6ffb2026 Mon Sep 17 00:00:00 2001 From: dscyrescotti Date: Thu, 23 May 2024 23:57:53 +0700 Subject: [PATCH 3/3] bug: correct memory layout format --- Memola/Canvas/RenderPasses/EraserRenderPass.swift | 2 +- Memola/Canvas/RenderPasses/StrokeRenderPass.swift | 2 +- Memola/Canvas/Shaders/Quad.metal | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Memola/Canvas/RenderPasses/EraserRenderPass.swift b/Memola/Canvas/RenderPasses/EraserRenderPass.swift index 32f115d..5290357 100644 --- a/Memola/Canvas/RenderPasses/EraserRenderPass.swift +++ b/Memola/Canvas/RenderPasses/EraserRenderPass.swift @@ -57,7 +57,7 @@ class EraserRenderPass: RenderPass { let quadCount = stroke.quads.endIndex var quads = stroke.quads let quadBuffer = renderer.device.makeBuffer(bytes: &quads, length: MemoryLayout.stride * quadCount, options: []) - let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 4, options: []) computeEncoder.setComputePipelineState(quadPipelineState) diff --git a/Memola/Canvas/RenderPasses/StrokeRenderPass.swift b/Memola/Canvas/RenderPasses/StrokeRenderPass.swift index 89945af..a9a4887 100644 --- a/Memola/Canvas/RenderPasses/StrokeRenderPass.swift +++ b/Memola/Canvas/RenderPasses/StrokeRenderPass.swift @@ -70,7 +70,7 @@ class StrokeRenderPass: RenderPass { let quadCount = stroke.quads.endIndex var quads = stroke.quads let quadBuffer = renderer.device.makeBuffer(bytes: &quads, length: MemoryLayout.stride * quadCount, options: []) - let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) + let indexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 6, options: []) let vertexBuffer = renderer.device.makeBuffer(length: MemoryLayout.stride * quadCount * 4, options: []) computeEncoder.setComputePipelineState(quadPipelineState) diff --git a/Memola/Canvas/Shaders/Quad.metal b/Memola/Canvas/Shaders/Quad.metal index 898c3d0..6f2d7c3 100644 --- a/Memola/Canvas/Shaders/Quad.metal +++ b/Memola/Canvas/Shaders/Quad.metal @@ -38,7 +38,7 @@ Vertex createVertex(Quad quad, float2 factor, float2 textCoord) { } kernel void generate_stroke_vertices( - device Quad *quads [[buffer(0)]], + constant Quad *quads [[buffer(0)]], device uint *indices [[buffer(1)]], device Vertex *vertices [[buffer(2)]], uint gid [[thread_position_in_grid]]