Nil*_*epa 4 stencil-buffer ios metal
我正在尝试学习如何在Metal IOS中实现模板缓冲区。目前,无需金属验证即可正常工作。但是,一旦我打开“金属验证”,项目就会崩溃。
这是我的代码:-金属视图:-
import MetalKit
class DrawingView: MTKView {
//Renderer to handle all the rendering of the Drawing View
public var renderer: Renderer!
override init(frame frameRect: CGRect, device: MTLDevice?) {
super.init(frame: frameRect, device: device)
self.configDrawingView()
}
required init(coder: NSCoder) {
super.init(coder: coder)
self.configDrawingView()
}
private func configDrawingView() {
//Setting system default GPU
self.device = MTLCreateSystemDefaultDevice()
//Setting pixel format for the view
self.colorPixelFormat = MTLPixelFormat.bgra8Unorm
//Setting clear color of the view. View will be cleared in every frame
self.clearColor = MTLClearColorMake(1.0, 1.0, 1.0, 1.0)
//Setting sample count of drawing textures
self.sampleCount = 1
//Setting prefered frame rate
self.preferredFramesPerSecond = 120
//Setting auto resizing of the drawable to false. If the value is true, the currentDrawable object’s texture, depthStencilTexture object, and multisampleColorTexture object automatically resize as the view resizes. If the value is false, drawableSize does not change and neither does the size of these objects.
self.autoResizeDrawable = false
//Stencil
self.clearStencil = 0
self.depthStencilPixelFormat = MTLPixelFormat.depth32Float_stencil8
//Setting up Renderer
self.renderer = Renderer(withDevice: self.device!)
//Using renderer and the MTKView delegate. This will call draw method every frame
self.delegate = renderer
}
}
Run Code Online (Sandbox Code Playgroud)
渲染器:
import MetalKit
class Renderer: NSObject {
//Device
private var device: MTLDevice!
//CommandQueue
private var commandQueue: MTLCommandQueue!
//Mirror Vertex
private var paintData: [Vertex] = [
Vertex(position: float4(-0.75, -0.75, 0, 1), color: float4(1.0, 1.0, 0.0, 1.0)),
Vertex(position: float4(-0.75, 0.75, 0, 1), color: float4(1.0, 1.0, 0.0, 1.0)),
Vertex(position: float4(0.75, 0.75, 0, 1), color: float4(1.0, 1.0, 0.0, 1.0)),
Vertex(position: float4(0.75, -0.75, 0, 1), color: float4(1.0, 1.0, 0.0, 1.0))
]
//Mirror Indices
private var paintIndicies: [UInt32] = [0, 1, 2, 0, 2, 3]
//Mirror Vertex Buffer
private var paintVertexBuffer: MTLBuffer!
//Mirror Index Buffer
private var paintIndexBuffer: MTLBuffer!
//Paint Vertex
private var stencilData: [Vertex] = [
Vertex(position: float4(-1, 0, 0, 1), color: float4(0.0, 0.0, 1.0, 1.0)),
Vertex(position: float4(0, 1, 0, 1), color: float4(0.0, 0.0, 1.0, 1.0)),
Vertex(position: float4(0, -1, 0, 1), color: float4(0.0, 0.0, 1.0, 1.0)),
Vertex(position: float4(1, 0, 0, 1), color: float4(0.0, 0.0, 1.0, 1.0))
]
//Paint indices
private var stencilIndices: [UInt32] = [0, 1, 2, 2, 1, 3]
//Paint Vertex Buffer
private var stencilVertexBuffer: MTLBuffer!
//Paint Index Buffer
private var stencilIndexBuffer: MTLBuffer!
//Depth Stencil State
private var depthStencilState: MTLDepthStencilState!
private var maskStencilState: MTLDepthStencilState!
private var drawStencilState: MTLDepthStencilState!
private var library: MTLLibrary!
private var vertexFunction: MTLFunction!
private var fragmentFunction: MTLFunction!
private var stencilFragmentFunction: MTLFunction!
private var pipelineState: MTLRenderPipelineState!
private var stencilPipelineState: MTLRenderPipelineState!
init(withDevice device: MTLDevice) {
super.init()
self.device = device
self.configure()
}
private func configure() {
self.commandQueue = self.device.makeCommandQueue()
self.setupPipelines()
self.setupDepthStencil()
self.setupBuffers()
}
private func setupDepthStencil() {
var depthStencilStateDescriptor: MTLDepthStencilDescriptor = MTLDepthStencilDescriptor()
depthStencilStateDescriptor.depthCompareFunction = MTLCompareFunction.less
depthStencilStateDescriptor.isDepthWriteEnabled = true
self.depthStencilState = self.device.makeDepthStencilState(descriptor: depthStencilStateDescriptor)
depthStencilStateDescriptor = MTLDepthStencilDescriptor()
depthStencilStateDescriptor.depthCompareFunction = MTLCompareFunction.less
var stencilDescriptor: MTLStencilDescriptor = MTLStencilDescriptor()
stencilDescriptor.stencilCompareFunction = MTLCompareFunction.always
stencilDescriptor.depthStencilPassOperation = MTLStencilOperation.replace
depthStencilStateDescriptor.backFaceStencil = stencilDescriptor
depthStencilStateDescriptor.frontFaceStencil = stencilDescriptor
depthStencilStateDescriptor.isDepthWriteEnabled = false
self.drawStencilState = self.device.makeDepthStencilState(descriptor: depthStencilStateDescriptor)
depthStencilStateDescriptor = MTLDepthStencilDescriptor()
depthStencilStateDescriptor.depthCompareFunction = MTLCompareFunction.less
stencilDescriptor = MTLStencilDescriptor()
stencilDescriptor.stencilCompareFunction = MTLCompareFunction.equal
depthStencilStateDescriptor.frontFaceStencil = stencilDescriptor
depthStencilStateDescriptor.backFaceStencil = stencilDescriptor
depthStencilStateDescriptor.isDepthWriteEnabled = true
self.maskStencilState = self.device.makeDepthStencilState(descriptor: depthStencilStateDescriptor)
}
private func setupPipelines() {
self.library = self.device.makeDefaultLibrary()
self.vertexFunction = self.library.makeFunction(name: "vertexShader")
self.fragmentFunction = self.library.makeFunction(name: "fragmentShader")
self.stencilFragmentFunction = self.library.makeFunction(name: "stencilFragmentShader")
var renderPipelineDescriptor: MTLRenderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexFunction = self.vertexFunction
renderPipelineDescriptor.fragmentFunction = self.fragmentFunction
renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm
renderPipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormat.depth32Float_stencil8
renderPipelineDescriptor.stencilAttachmentPixelFormat = MTLPixelFormat.depth32Float_stencil8
do {
self.pipelineState = try self.device.makeRenderPipelineState(descriptor: renderPipelineDescriptor)
} catch {
print("\(error)")
}
var renderPipelineDescriptorNoDraw: MTLRenderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptorNoDraw.vertexFunction = self.vertexFunction
renderPipelineDescriptorNoDraw.fragmentFunction = self.stencilFragmentFunction
renderPipelineDescriptorNoDraw.depthAttachmentPixelFormat = MTLPixelFormat.depth32Float_stencil8
renderPipelineDescriptorNoDraw.stencilAttachmentPixelFormat = MTLPixelFormat.depth32Float_stencil8
renderPipelineDescriptorNoDraw.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm //Problem Here ---- (1)
renderPipelineDescriptorNoDraw.colorAttachments[0].writeMask = []
do {
self.stencilPipelineState = try self.device.makeRenderPipelineState(descriptor: renderPipelineDescriptorNoDraw)
} catch {
print("\(error)")
}
}
private func setupBuffers() {
self.stencilVertexBuffer = self.device.makeBuffer(bytes: self.stencilData, length: MemoryLayout<Vertex>.stride * self.stencilData.count, options: [])
self.stencilIndexBuffer = self.device.makeBuffer(bytes: self.stencilIndices, length: MemoryLayout<UInt32>.size * self.stencilIndices.count, options: [])
self.paintVertexBuffer = self.device.makeBuffer(bytes: self.paintData, length: MemoryLayout<Vertex>.stride * self.paintData.count, options: [])
self.paintIndexBuffer = self.device.makeBuffer(bytes: self.paintIndicies, length: MemoryLayout<UInt32>.size * self.paintIndicies.count, options: [])
}
}
extension Renderer: MTKViewDelegate {
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
}
func draw(in view: MTKView) {
let buffer: MTLCommandBuffer = self.commandQueue.makeCommandBuffer()!
let renderPassDescriptor = view.currentRenderPassDescriptor
renderPassDescriptor!.colorAttachments[0].clearColor = MTLClearColorMake(1.0, 1.0, 1.0, 1.0)
let encoderClear = buffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
encoderClear!.endEncoding()
let renderPassDescriptorOther = MTLRenderPassDescriptor()
renderPassDescriptorOther.colorAttachments[0].loadAction = MTLLoadAction.load
renderPassDescriptorOther.colorAttachments[0].storeAction = MTLStoreAction.store
renderPassDescriptorOther.colorAttachments[0].texture = view.currentDrawable?.texture
let commandEncoderOther = buffer.makeRenderCommandEncoder(descriptor: renderPassDescriptorOther)
Plane(withDevice: self.device, sizeOf: float2(100, 100), andPlaneCenterTo: float2(100, 100), withColor: float4(1.0, 0.0, 0.0, 1.0)).render(commandEncoder: commandEncoderOther!)
commandEncoderOther?.endEncoding()
let renderPassDescriptorOther1 = MTLRenderPassDescriptor()
renderPassDescriptorOther1.colorAttachments[0].loadAction = MTLLoadAction.load
renderPassDescriptorOther1.colorAttachments[0].storeAction = MTLStoreAction.store
renderPassDescriptorOther1.colorAttachments[0].texture = view.currentDrawable?.texture
let encoder: MTLRenderCommandEncoder = buffer.makeRenderCommandEncoder(descriptor: renderPassDescriptorOther1)!
//Stencil
encoder.setRenderPipelineState(self.stencilPipelineState)
encoder.setStencilReferenceValue(1)
encoder.setDepthStencilState(self.drawStencilState)
encoder.setVertexBuffer(self.stencilVertexBuffer, offset: 0, index: 0)
encoder.drawIndexedPrimitives(type: MTLPrimitiveType.triangle, indexCount: self.stencilIndices.count, indexType: MTLIndexType.uint32, indexBuffer: self.stencilIndexBuffer, indexBufferOffset: 0)
//Paint
encoder.setRenderPipelineState(self.pipelineState)
encoder.setDepthStencilState(self.maskStencilState)
encoder.setVertexBuffer(self.paintVertexBuffer, offset: 0, index: 0)
encoder.drawIndexedPrimitives(type: MTLPrimitiveType.triangle, indexCount: self.paintIndicies.count, indexType: MTLIndexType.uint32, indexBuffer: self.paintIndexBuffer, indexBufferOffset: 0)
encoder.endEncoding()
buffer.present(view.currentDrawable!)
buffer.commit()
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的着色器文件:
#include <metal_stdlib>
using namespace metal;
struct Vertex {
float4 position [[position]];
float4 color;
};
vertex Vertex vertexShader(const device Vertex *vertexArray [[buffer(0)]], unsigned int vid [[vertex_id]]) {
return vertexArray[vid];
}
fragment float4 fragmentShader(Vertex interpolated [[stage_in]]) {
return interpolated.color;
}
fragment float4 fragmentShader_stencil(Vertex v [[stage_in]])
{
return float4(1, 1, 1, 0.0);
}
Run Code Online (Sandbox Code Playgroud)
当我打开金属验证时,它给了我这个错误:
[MTLDebugRenderCommandEncoder validateFramebufferWithRenderPipelineState:]:1236:
failed assertion `For depth attachment, the renderPipelineState pixelFormat
must be MTLPixelFormatInvalid, as no texture is set.'
Run Code Online (Sandbox Code Playgroud)
然后我在Renderer中更改了(1)像素格式,MTLPixelFormat.inavlid这给了我另一个错误:-
[MTLDebugRenderCommandEncoder validateFramebufferWithRenderPipelineState:]:1196:
failed assertion `For color attachment 0, the render pipeline's pixelFormat
(MTLPixelFormatInvalid) does not match the framebuffer's pixelFormat
(MTLPixelFormatBGRA8Unorm).'
Run Code Online (Sandbox Code Playgroud)
有没有办法解决这个问题。我希望启用金属验证。禁用验证后,它可以正常工作。
由于您是手动创建渲染过程描述符,因此需要确保配置了所有相关附件的纹理和加载/存储操作。
您已经指定了MTKView它应该为您管理深度/模板纹理,并配置了渲染管道状态以期望深度/模板纹理,因此在创建渲染过程描述符时需要提供这样的纹理:
renderPassDescriptorOther1.depthAttachment.loadAction = .clear
renderPassDescriptorOther1.depthAttachment.storeAction = .dontCare
renderPassDescriptorOther1.depthAttachment.texture = view.depthStencilTexture
renderPassDescriptorOther1.stencilAttachment.loadAction = .clear
renderPassDescriptorOther1.stencilAttachment.storeAction = .dontCare
renderPassDescriptorOther1.stencilAttachment.texture = view.depthStencilTexture
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我看不出在绘制之前进行单独的“清除”传递的原因。看来您可以将loadActionof renderPassDescriptorOther的颜色附件设置为.clear。
| 归档时间: |
|
| 查看次数: |
114 次 |
| 最近记录: |