From acf8e83cbf106b4350536d54eb46379dd86a623c Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Fri, 04 Jul 2025 17:05:00 +0000 Subject: [PATCH] 输入弹框 图标修改 相机调整 --- LiveProject/tool/MetalRenderer.swift | 134 ++++++++++++++++++++++++++------------------ 1 files changed, 79 insertions(+), 55 deletions(-) diff --git a/LiveProject/tool/MetalRenderer.swift b/LiveProject/tool/MetalRenderer.swift index 3e88871..61bd769 100644 --- a/LiveProject/tool/MetalRenderer.swift +++ b/LiveProject/tool/MetalRenderer.swift @@ -4,75 +4,99 @@ // 渲染工具 // Created by 倪路朋 on 6/26/25. // +import Foundation import Metal import MetalKit +import AVFoundation -class Renderer: NSObject, MTKViewDelegate { - static var shared: Renderer? +class MetalRenderer: NSObject, MTKViewDelegate { + private let device: MTLDevice + private let commandQueue: MTLCommandQueue + private let ciContext: CIContext - 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 currentPixelBuffer: CVPixelBuffer? + private let textureCache: CVMetalTextureCache - 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 + init(mtkView: MTKView) { + guard let device = MTLCreateSystemDefaultDevice(), + let commandQueue = device.makeCommandQueue() else { + fatalError("Unable to create Metal device or command queue") } - } - func updateFrame(data: [UInt8], width: Int, height: Int) { - currentData = data - textureWidth = width - textureHeight = height + self.device = device + self.commandQueue = commandQueue + self.ciContext = CIContext(mtlDevice: device) + + var tmpCache: CVMetalTextureCache? + CVMetalTextureCacheCreate(nil, nil, device, nil, &tmpCache) + guard let textureCache = tmpCache else { + fatalError("Unable to create texture cache") + } + self.textureCache = textureCache + + super.init() + + // ✅ 设置驱动渲染的关键代码 + mtkView.device = device + mtkView.framebufferOnly = false + mtkView.isPaused = false + mtkView.enableSetNeedsDisplay = false + mtkView.delegate = self + print("MetalRenderer init") } func draw(in view: MTKView) { + let size = view.drawableSize + //print("🧾 drawableSize = \(size)") + + if !size.width.isFinite || !size.height.isFinite || size.width <= 0 || size.height <= 0 { + print("❌ 非法尺寸,跳过渲染 \(size)") + return + } guard let drawable = view.currentDrawable, - let descriptor = view.currentRenderPassDescriptor, - let data = currentData 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) + let commandBuffer = commandQueue.makeCommandBuffer(), + let pixelBuffer = currentPixelBuffer else { + return } - let region = MTLRegionMake2D(0, 0, textureWidth, textureHeight) - data.withUnsafeBytes { ptr in - texture?.replace(region: region, mipmapLevel: 0, withBytes: ptr.baseAddress!, bytesPerRow: textureWidth * 4) - } + let drawableSize = view.drawableSize + guard drawableSize.width > 0, drawableSize.height > 0 else { return } - 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() + // 加方向修正:顺时针旋转90度 + var ciImage = CIImage(cvPixelBuffer: pixelBuffer).oriented(.right) + + // 等比缩放后居中 + let sourceExtent = ciImage.extent + let scaleX = drawableSize.width / sourceExtent.width + let scaleY = drawableSize.height / sourceExtent.height + let scale = min(scaleX, scaleY) + + let scaledImage = ciImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale)) + + let xOffset = (drawableSize.width - scaledImage.extent.width) / 2 + let yOffset = (drawableSize.height - scaledImage.extent.height) / 2 + let translatedImage = scaledImage.transformed(by: CGAffineTransform(translationX: xOffset, y: yOffset)) + + // 渲染 + ciContext.render(translatedImage, + to: drawable.texture, + commandBuffer: commandBuffer, + bounds: CGRect(origin: .zero, size: drawableSize), + colorSpace: CGColorSpaceCreateDeviceRGB()) + + commandBuffer.present(drawable) + commandBuffer.commit() + //print("绘制画面") } - func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {} + func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { + // No-op: Handle size change if needed + } + + func display(pixelBuffer: CVPixelBuffer) { + self.currentPixelBuffer = pixelBuffer + //print("display") + //刷新 + + } } -- Gitblit v1.9.1