mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-03 21:21:34 +00:00
split core renderer stuff into metal subfolder
This commit is contained in:
@ -49,6 +49,13 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
|||||||
Renderer/BlendMode.swift
|
Renderer/BlendMode.swift
|
||||||
Renderer/BlendFunc.swift
|
Renderer/BlendFunc.swift
|
||||||
Renderer/ChunkRenderer.swift
|
Renderer/ChunkRenderer.swift
|
||||||
|
Renderer/Metal/BlendFuncExtension.swift
|
||||||
|
Renderer/Metal/ColorExtension.swift
|
||||||
|
Renderer/Metal/EnvironmentExtension.swift
|
||||||
|
Renderer/Metal/PipelineOptions.swift
|
||||||
|
Renderer/Metal/Shader.swift
|
||||||
|
Renderer/Metal/RendererMesh.swift
|
||||||
|
Renderer/RendererError.swift
|
||||||
Renderer/Renderer.swift
|
Renderer/Renderer.swift
|
||||||
|
|
||||||
# Input wrappers
|
# Input wrappers
|
||||||
@ -144,4 +151,5 @@ source_group("Source Files\\Noise" REGULAR_EXPRESSION "Noise/")
|
|||||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
||||||
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
|
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
|
||||||
source_group("Source Files\\Renderer" REGULAR_EXPRESSION "Renderer/")
|
source_group("Source Files\\Renderer" REGULAR_EXPRESSION "Renderer/")
|
||||||
|
source_group("Source Files\\Renderer\\Metal" REGULAR_EXPRESSION "Renderer/Metal/")
|
||||||
source_group("Source Files\\Generator" REGULAR_EXPRESSION "Generator/")
|
source_group("Source Files\\Generator" REGULAR_EXPRESSION "Generator/")
|
||||||
|
87
Sources/Voxelotl/Renderer/Metal/BlendFuncExtension.swift
Normal file
87
Sources/Voxelotl/Renderer/Metal/BlendFuncExtension.swift
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
internal extension BlendFunc {
|
||||||
|
func setBlend(colorAttachment: inout MTLRenderPipelineColorAttachmentDescriptor) {
|
||||||
|
switch self {
|
||||||
|
case .off:
|
||||||
|
colorAttachment.isBlendingEnabled = false
|
||||||
|
case .on(let srcFactor, let dstFactor, let equation):
|
||||||
|
colorAttachment.isBlendingEnabled = true
|
||||||
|
colorAttachment.rgbBlendOperation = .init(equation)
|
||||||
|
colorAttachment.alphaBlendOperation = .init(equation)
|
||||||
|
colorAttachment.sourceRGBBlendFactor = .init(srcFactor)
|
||||||
|
colorAttachment.sourceAlphaBlendFactor = .init(srcFactor)
|
||||||
|
colorAttachment.destinationRGBBlendFactor = .init(dstFactor)
|
||||||
|
colorAttachment.destinationAlphaBlendFactor = .init(dstFactor)
|
||||||
|
case .separate(let srcColor, let srcAlpha, let dstColor, let dstAlpha, let equColor, let equAlpha):
|
||||||
|
colorAttachment.isBlendingEnabled = true
|
||||||
|
colorAttachment.rgbBlendOperation = .init(equColor)
|
||||||
|
colorAttachment.alphaBlendOperation = .init(equAlpha)
|
||||||
|
colorAttachment.sourceRGBBlendFactor = .init(srcColor)
|
||||||
|
colorAttachment.sourceAlphaBlendFactor = .init(srcAlpha)
|
||||||
|
colorAttachment.destinationRGBBlendFactor = .init(dstColor)
|
||||||
|
colorAttachment.destinationAlphaBlendFactor = .init(dstAlpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal extension MTLBlendOperation {
|
||||||
|
init(_ equation: BlendFuncEquation) {
|
||||||
|
self = switch equation {
|
||||||
|
case .add: .add
|
||||||
|
case .subtract: .subtract
|
||||||
|
case .reverseSubtract: .reverseSubtract
|
||||||
|
case .min: .min
|
||||||
|
case .max: .max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal extension MTLBlendFactor {
|
||||||
|
init(_ source: BlendFuncSourceFactor) {
|
||||||
|
self = switch source {
|
||||||
|
case .zero: .zero
|
||||||
|
case .one: .one
|
||||||
|
case .srcColor: .sourceColor
|
||||||
|
case .oneMinusSrcColor: .oneMinusSourceColor
|
||||||
|
case .srcAlpha: .sourceAlpha
|
||||||
|
case .oneMinusSrcAlpha: .oneMinusSourceAlpha
|
||||||
|
case .dstColor: .destinationColor
|
||||||
|
case .oneMinusDstColor: .oneMinusDestinationColor
|
||||||
|
case .dstAlpha: .destinationAlpha
|
||||||
|
case .oneMinusDstAlpha: .oneMinusDestinationAlpha
|
||||||
|
case .srcAlphaSaturate: .sourceAlphaSaturated
|
||||||
|
/*
|
||||||
|
case .constantColor: .blendColor
|
||||||
|
case .oneMinusConstantColor: .oneMinusBlendColor
|
||||||
|
case .constantAlpha: .blendAlpha
|
||||||
|
case .oneMinusConstantAlpha: .oneMinusBlendAlpha
|
||||||
|
*/
|
||||||
|
case .src1Color: .source1Color
|
||||||
|
case .oneMinusSrc1Color: .oneMinusSource1Color
|
||||||
|
case .src1Alpha: .source1Alpha
|
||||||
|
case .oneMinusSrc1Alpha: .oneMinusSource1Alpha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ destination: BlendFuncDestinationFactor) {
|
||||||
|
self = switch destination {
|
||||||
|
case .zero: .zero
|
||||||
|
case .one: .one
|
||||||
|
case .srcColor: .sourceColor
|
||||||
|
case .oneMinusSrcColor: .oneMinusSourceColor
|
||||||
|
case .srcAlpha: .sourceAlpha
|
||||||
|
case .oneMinusSrcAlpha: .oneMinusSourceAlpha
|
||||||
|
case .dstColor: .destinationColor
|
||||||
|
case .oneMinusDstColor: .oneMinusDestinationColor
|
||||||
|
case .dstAlpha: .destinationAlpha
|
||||||
|
case .oneMinusDstAlpha: .oneMinusDestinationAlpha
|
||||||
|
/*
|
||||||
|
case .constantColor: .blendColor
|
||||||
|
case .oneMinusConstantColor: .oneMinusBlendColor
|
||||||
|
case .constantAlpha: .blendAlpha
|
||||||
|
case .oneMinusConstantAlpha: .oneMinusBlendAlpha
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Sources/Voxelotl/Renderer/Metal/ColorExtension.swift
Normal file
7
Sources/Voxelotl/Renderer/Metal/ColorExtension.swift
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
internal extension MTLClearColor {
|
||||||
|
init(_ color: Color<Double>) {
|
||||||
|
self.init(red: color.r, green: color.g, blue: color.b, alpha: color.a)
|
||||||
|
}
|
||||||
|
}
|
11
Sources/Voxelotl/Renderer/Metal/EnvironmentExtension.swift
Normal file
11
Sources/Voxelotl/Renderer/Metal/EnvironmentExtension.swift
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
internal extension MTLCullMode {
|
||||||
|
init(_ face: Environment.Face) {
|
||||||
|
self = switch face {
|
||||||
|
case .none: .none
|
||||||
|
case .front: .front
|
||||||
|
case .back: .back
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Sources/Voxelotl/Renderer/Metal/PipelineOptions.swift
Normal file
23
Sources/Voxelotl/Renderer/Metal/PipelineOptions.swift
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
internal struct PipelineOptions: Hashable {
|
||||||
|
let colorFormat: MTLPixelFormat, depthFormat: MTLPixelFormat
|
||||||
|
let shader: Shader
|
||||||
|
let blendFunc: BlendFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
internal extension PipelineOptions {
|
||||||
|
func createPipeline(_ device: MTLDevice) throws -> MTLRenderPipelineState {
|
||||||
|
let pipeDescription = MTLRenderPipelineDescriptor()
|
||||||
|
pipeDescription.vertexFunction = self.shader.vertexProgram
|
||||||
|
pipeDescription.fragmentFunction = self.shader.fragmentProgram
|
||||||
|
pipeDescription.colorAttachments[0].pixelFormat = self.colorFormat
|
||||||
|
self.blendFunc.setBlend(colorAttachment: &pipeDescription.colorAttachments[0])
|
||||||
|
pipeDescription.depthAttachmentPixelFormat = self.depthFormat
|
||||||
|
do {
|
||||||
|
return try device.makeRenderPipelineState(descriptor: pipeDescription)
|
||||||
|
} catch {
|
||||||
|
throw RendererError.initFailure("Failed to create pipeline state: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
Sources/Voxelotl/Renderer/Metal/RendererMesh.swift
Normal file
18
Sources/Voxelotl/Renderer/Metal/RendererMesh.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
public struct RendererMesh: Hashable {
|
||||||
|
internal let _vertBuf: MTLBuffer, _idxBuf: MTLBuffer
|
||||||
|
public let numIndices: Int
|
||||||
|
|
||||||
|
public static func == (lhs: Self, rhs: Self) -> Bool {
|
||||||
|
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
|
||||||
|
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
|
||||||
|
lhs.numIndices == rhs.numIndices
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
hasher.combine(self._vertBuf.hash)
|
||||||
|
hasher.combine(self._idxBuf.hash)
|
||||||
|
hasher.combine(self.numIndices)
|
||||||
|
}
|
||||||
|
}
|
14
Sources/Voxelotl/Renderer/Metal/Shader.swift
Normal file
14
Sources/Voxelotl/Renderer/Metal/Shader.swift
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import Metal
|
||||||
|
|
||||||
|
internal struct Shader: Hashable {
|
||||||
|
let vertexProgram: (any MTLFunction)?, fragmentProgram: (any MTLFunction)?
|
||||||
|
|
||||||
|
static func == (lhs: Shader, rhs: Shader) -> Bool {
|
||||||
|
lhs.vertexProgram?.hash == rhs.vertexProgram?.hash && lhs.fragmentProgram?.hash == rhs.fragmentProgram?.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
hasher.combine(self.vertexProgram?.hash ?? 0)
|
||||||
|
hasher.combine(self.fragmentProgram?.hash ?? 0)
|
||||||
|
}
|
||||||
|
}
|
@ -516,163 +516,3 @@ public class Renderer {
|
|||||||
instanceCount: numInstances)
|
instanceCount: numInstances)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct RendererMesh: Hashable {
|
|
||||||
fileprivate let _vertBuf: MTLBuffer, _idxBuf: MTLBuffer
|
|
||||||
public let numIndices: Int
|
|
||||||
|
|
||||||
public static func == (lhs: Self, rhs: Self) -> Bool {
|
|
||||||
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
|
|
||||||
lhs._vertBuf.gpuAddress == rhs._vertBuf.gpuAddress && lhs._vertBuf.length == rhs._vertBuf.length &&
|
|
||||||
lhs.numIndices == rhs.numIndices
|
|
||||||
}
|
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
|
||||||
hasher.combine(self._vertBuf.hash)
|
|
||||||
hasher.combine(self._idxBuf.hash)
|
|
||||||
hasher.combine(self.numIndices)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension MTLClearColor {
|
|
||||||
init(_ color: Color<Double>) {
|
|
||||||
self.init(red: color.r, green: color.g, blue: color.b, alpha: color.a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension MTLCullMode {
|
|
||||||
init(_ face: Environment.Face) {
|
|
||||||
self = switch face {
|
|
||||||
case .none: .none
|
|
||||||
case .front: .front
|
|
||||||
case .back: .back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate struct Shader: Hashable {
|
|
||||||
let vertexProgram: (any MTLFunction)?, fragmentProgram: (any MTLFunction)?
|
|
||||||
|
|
||||||
static func == (lhs: Shader, rhs: Shader) -> Bool {
|
|
||||||
lhs.vertexProgram?.hash == rhs.vertexProgram?.hash && lhs.fragmentProgram?.hash == rhs.fragmentProgram?.hash
|
|
||||||
}
|
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
|
||||||
hasher.combine(self.vertexProgram?.hash ?? 0)
|
|
||||||
hasher.combine(self.fragmentProgram?.hash ?? 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate struct PipelineOptions: Hashable {
|
|
||||||
let colorFormat: MTLPixelFormat, depthFormat: MTLPixelFormat
|
|
||||||
let shader: Shader
|
|
||||||
let blendFunc: BlendFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension PipelineOptions {
|
|
||||||
func createPipeline(_ device: MTLDevice) throws -> MTLRenderPipelineState {
|
|
||||||
let pipeDescription = MTLRenderPipelineDescriptor()
|
|
||||||
pipeDescription.vertexFunction = self.shader.vertexProgram
|
|
||||||
pipeDescription.fragmentFunction = self.shader.fragmentProgram
|
|
||||||
pipeDescription.colorAttachments[0].pixelFormat = self.colorFormat
|
|
||||||
self.blendFunc.setBlend(colorAttachment: &pipeDescription.colorAttachments[0])
|
|
||||||
pipeDescription.depthAttachmentPixelFormat = self.depthFormat
|
|
||||||
do {
|
|
||||||
return try device.makeRenderPipelineState(descriptor: pipeDescription)
|
|
||||||
} catch {
|
|
||||||
throw RendererError.initFailure("Failed to create pipeline state: \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension BlendFunc {
|
|
||||||
func setBlend(colorAttachment: inout MTLRenderPipelineColorAttachmentDescriptor) {
|
|
||||||
switch self {
|
|
||||||
case .off:
|
|
||||||
colorAttachment.isBlendingEnabled = false
|
|
||||||
case .on(let srcFactor, let dstFactor, let equation):
|
|
||||||
colorAttachment.isBlendingEnabled = true
|
|
||||||
colorAttachment.rgbBlendOperation = .init(equation)
|
|
||||||
colorAttachment.alphaBlendOperation = .init(equation)
|
|
||||||
colorAttachment.sourceRGBBlendFactor = .init(srcFactor)
|
|
||||||
colorAttachment.sourceAlphaBlendFactor = .init(srcFactor)
|
|
||||||
colorAttachment.destinationRGBBlendFactor = .init(dstFactor)
|
|
||||||
colorAttachment.destinationAlphaBlendFactor = .init(dstFactor)
|
|
||||||
case .separate(let srcColor, let srcAlpha, let dstColor, let dstAlpha, let equColor, let equAlpha):
|
|
||||||
colorAttachment.isBlendingEnabled = true
|
|
||||||
colorAttachment.rgbBlendOperation = .init(equColor)
|
|
||||||
colorAttachment.alphaBlendOperation = .init(equAlpha)
|
|
||||||
colorAttachment.sourceRGBBlendFactor = .init(srcColor)
|
|
||||||
colorAttachment.sourceAlphaBlendFactor = .init(srcAlpha)
|
|
||||||
colorAttachment.destinationRGBBlendFactor = .init(dstColor)
|
|
||||||
colorAttachment.destinationAlphaBlendFactor = .init(dstAlpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension MTLBlendOperation {
|
|
||||||
init(_ equation: BlendFuncEquation) {
|
|
||||||
self = switch equation {
|
|
||||||
case .add: .add
|
|
||||||
case .subtract: .subtract
|
|
||||||
case .reverseSubtract: .reverseSubtract
|
|
||||||
case .min: .min
|
|
||||||
case .max: .max
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate extension MTLBlendFactor {
|
|
||||||
init(_ source: BlendFuncSourceFactor) {
|
|
||||||
self = switch source {
|
|
||||||
case .zero: .zero
|
|
||||||
case .one: .one
|
|
||||||
case .srcColor: .sourceColor
|
|
||||||
case .oneMinusSrcColor: .oneMinusSourceColor
|
|
||||||
case .srcAlpha: .sourceAlpha
|
|
||||||
case .oneMinusSrcAlpha: .oneMinusSourceAlpha
|
|
||||||
case .dstColor: .destinationColor
|
|
||||||
case .oneMinusDstColor: .oneMinusDestinationColor
|
|
||||||
case .dstAlpha: .destinationAlpha
|
|
||||||
case .oneMinusDstAlpha: .oneMinusDestinationAlpha
|
|
||||||
case .srcAlphaSaturate: .sourceAlphaSaturated
|
|
||||||
/*
|
|
||||||
case .constantColor: .blendColor
|
|
||||||
case .oneMinusConstantColor: .oneMinusBlendColor
|
|
||||||
case .constantAlpha: .blendAlpha
|
|
||||||
case .oneMinusConstantAlpha: .oneMinusBlendAlpha
|
|
||||||
*/
|
|
||||||
case .src1Color: .source1Color
|
|
||||||
case .oneMinusSrc1Color: .oneMinusSource1Color
|
|
||||||
case .src1Alpha: .source1Alpha
|
|
||||||
case .oneMinusSrc1Alpha: .oneMinusSource1Alpha
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(_ destination: BlendFuncDestinationFactor) {
|
|
||||||
self = switch destination {
|
|
||||||
case .zero: .zero
|
|
||||||
case .one: .one
|
|
||||||
case .srcColor: .sourceColor
|
|
||||||
case .oneMinusSrcColor: .oneMinusSourceColor
|
|
||||||
case .srcAlpha: .sourceAlpha
|
|
||||||
case .oneMinusSrcAlpha: .oneMinusSourceAlpha
|
|
||||||
case .dstColor: .destinationColor
|
|
||||||
case .oneMinusDstColor: .oneMinusDestinationColor
|
|
||||||
case .dstAlpha: .destinationAlpha
|
|
||||||
case .oneMinusDstAlpha: .oneMinusDestinationAlpha
|
|
||||||
/*
|
|
||||||
case .constantColor: .blendColor
|
|
||||||
case .oneMinusConstantColor: .oneMinusBlendColor
|
|
||||||
case .constantAlpha: .blendAlpha
|
|
||||||
case .oneMinusConstantAlpha: .oneMinusBlendAlpha
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum RendererError: Error {
|
|
||||||
case initFailure(_ message: String)
|
|
||||||
case loadFailure(_ message: String)
|
|
||||||
case drawFailure(_ message: String)
|
|
||||||
}
|
|
||||||
|
5
Sources/Voxelotl/Renderer/RendererError.swift
Normal file
5
Sources/Voxelotl/Renderer/RendererError.swift
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
enum RendererError: Error {
|
||||||
|
case initFailure(_ message: String)
|
||||||
|
case loadFailure(_ message: String)
|
||||||
|
case drawFailure(_ message: String)
|
||||||
|
}
|
Reference in New Issue
Block a user