From e21b1c797955a231f2bcf71818e0259fbb6aeba1 Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Fri, 27 Jun 2025 15:57:25 +0000 Subject: [PATCH] 相机权限 --- LiveProject/tool/MetalRenderer.swift | 103 ++++++++++++++++++++++++--------------------------- 1 files changed, 48 insertions(+), 55 deletions(-) diff --git a/LiveProject/tool/MetalRenderer.swift b/LiveProject/tool/MetalRenderer.swift index 3e88871..a2aa4ba 100644 --- a/LiveProject/tool/MetalRenderer.swift +++ b/LiveProject/tool/MetalRenderer.swift @@ -4,75 +4,68 @@ // 渲染工具 // Created by 倪路朋 on 6/26/25. // -import Metal import MetalKit -class Renderer: NSObject, MTKViewDelegate { - static var shared: Renderer? - +class MetalRenderer: NSObject, MTKViewDelegate { private var device: MTLDevice! private var commandQueue: MTLCommandQueue! - private var pipelineState: MTLRenderPipelineState! - private var texture: MTLTexture? - private var textureDescriptor: MTLTextureDescriptor! - private var currentData: [UInt8]? - private var textureWidth = 0 - private var textureHeight = 0 + private var textureCache: CVMetalTextureCache! + private var currentPixelBuffer: CVPixelBuffer? - weak var mtkView: MTKView? { - didSet { - guard let view = mtkView else { return } - device = view.device - commandQueue = device.makeCommandQueue() - - let library = device.makeDefaultLibrary() - let pipelineDesc = MTLRenderPipelineDescriptor() - pipelineDesc.vertexFunction = library?.makeFunction(name: "vertexShader") - pipelineDesc.fragmentFunction = library?.makeFunction(name: "fragmentShader") - pipelineDesc.colorAttachments[0].pixelFormat = view.colorPixelFormat - - pipelineState = try? device.makeRenderPipelineState(descriptor: pipelineDesc) - - Renderer.shared = self - } + func setup(view: MTKView) { + self.device = view.device + self.commandQueue = device.makeCommandQueue() + CVMetalTextureCacheCreate(nil, nil, device, nil, &textureCache) } - func updateFrame(data: [UInt8], width: Int, height: Int) { - currentData = data - textureWidth = width - textureHeight = height + func updateFrame(pixelBuffer: CVPixelBuffer) { + self.currentPixelBuffer = pixelBuffer } + + func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {} func draw(in view: MTKView) { guard let drawable = view.currentDrawable, let descriptor = view.currentRenderPassDescriptor, - let data = currentData else { return } + let pixelBuffer = currentPixelBuffer else { return } - if texture == nil || texture?.width != textureWidth || texture?.height != textureHeight { - textureDescriptor = MTLTextureDescriptor.texture2DDescriptor( - pixelFormat: .rgba8Unorm, - width: textureWidth, - height: textureHeight, - mipmapped: false - ) - textureDescriptor.usage = [.shaderRead, .shaderWrite] - texture = device.makeTexture(descriptor: textureDescriptor) + var textureRef: CVMetalTexture? + let width = CVPixelBufferGetWidth(pixelBuffer) + let height = CVPixelBufferGetHeight(pixelBuffer) + + let status = CVMetalTextureCacheCreateTextureFromImage( + nil, textureCache, pixelBuffer, nil, + .bgra8Unorm, width, height, 0, &textureRef) + + guard status == kCVReturnSuccess, + let cvTexture = textureRef, + let texture = CVMetalTextureGetTexture(cvTexture) else { return } + + let commandBuffer = commandQueue.makeCommandBuffer()! + let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: descriptor)! + encoder.setFragmentTexture(texture, index: 0) + encoder.endEncoding() + + // 简单拷贝(不做 shader 处理) + let blitEncoder = commandBuffer.makeBlitCommandEncoder()! + let dstTexture = drawable.texture + if dstTexture.width != texture.width || dstTexture.height != texture.height { + print("❌ 尺寸不一致,无法 blit:src = \(texture.width)x\(texture.height), dst = \(dstTexture.width)x\(dstTexture.height)") + return } + blitEncoder.copy(from: texture, + sourceSlice: 0, + sourceLevel: 0, + sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), + sourceSize: MTLSize(width: width, height: height, depth: 1), + to: drawable.texture, + destinationSlice: 0, + destinationLevel: 0, + destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0)) + blitEncoder.endEncoding() - let region = MTLRegionMake2D(0, 0, textureWidth, textureHeight) - data.withUnsafeBytes { ptr in - texture?.replace(region: region, mipmapLevel: 0, withBytes: ptr.baseAddress!, bytesPerRow: textureWidth * 4) - } - - let commandBuffer = commandQueue.makeCommandBuffer() - let encoder = commandBuffer?.makeRenderCommandEncoder(descriptor: descriptor) - encoder?.setRenderPipelineState(pipelineState) - encoder?.setFragmentTexture(texture, index: 0) - encoder?.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4) - encoder?.endEncoding() - commandBuffer?.present(drawable) - commandBuffer?.commit() + commandBuffer.present(drawable) + commandBuffer.commit() + print("绘制画面") } - - func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {} } -- Gitblit v1.9.1