//
|
// Renderer.swift
|
// LiveProject
|
// 渲染工具
|
// Created by 倪路朋 on 6/26/25.
|
//
|
import MetalKit
|
|
class MetalRenderer: NSObject, MTKViewDelegate {
|
private var device: MTLDevice!
|
private var commandQueue: MTLCommandQueue!
|
private var textureCache: CVMetalTextureCache!
|
private var currentPixelBuffer: CVPixelBuffer?
|
|
func setup(view: MTKView) {
|
self.device = view.device
|
self.commandQueue = device.makeCommandQueue()
|
CVMetalTextureCacheCreate(nil, nil, device, nil, &textureCache)
|
}
|
|
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 pixelBuffer = currentPixelBuffer else { return }
|
|
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()
|
|
commandBuffer.present(drawable)
|
commandBuffer.commit()
|
print("绘制画面")
|
}
|
}
|