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