From 3b7521a47ae731f0bf0a922822e4417493489539 Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Wed, 09 Jul 2025 10:42:02 +0000 Subject: [PATCH] 小窗布局,小窗移动 --- LiveProject/tool/MetalRenderer.swift | 102 +++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 83 insertions(+), 19 deletions(-) diff --git a/LiveProject/tool/MetalRenderer.swift b/LiveProject/tool/MetalRenderer.swift index 791dfc8..61bd769 100644 --- a/LiveProject/tool/MetalRenderer.swift +++ b/LiveProject/tool/MetalRenderer.swift @@ -4,35 +4,99 @@ // 渲染工具 // Created by 倪路朋 on 6/26/25. // -import CoreVideo +import Foundation import Metal import MetalKit +import AVFoundation class MetalRenderer: NSObject, MTKViewDelegate { - var device: MTLDevice! - var commandQueue: MTLCommandQueue! + private let device: MTLDevice + private let commandQueue: MTLCommandQueue + private let ciContext: CIContext - func setup(view: MTKView) { - self.device = view.device - self.commandQueue = device.makeCommandQueue() - // 初始化 texture、pipeline 等 + private var currentPixelBuffer: CVPixelBuffer? + private let textureCache: CVMetalTextureCache + + init(mtkView: MTKView) { + guard let device = MTLCreateSystemDefaultDevice(), + let commandQueue = device.makeCommandQueue() else { + fatalError("Unable to create Metal device or command queue") + } + + 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") } - // ✅ 必须实现的方法 1:窗口大小改变时调用 - func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { - // 可以留空或更新视图缩放、渲染区域等 - } - - // ✅ 必须实现的方法 2:每一帧绘制时调用 func draw(in view: MTKView) { - guard let drawable = view.currentDrawable, - let descriptor = view.currentRenderPassDescriptor else { return } + let size = view.drawableSize + //print("🧾 drawableSize = \(size)") - let commandBuffer = commandQueue.makeCommandBuffer()! - let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: descriptor)! - // 渲染逻辑,如绘制纹理 - encoder.endEncoding() + if !size.width.isFinite || !size.height.isFinite || size.width <= 0 || size.height <= 0 { + print("❌ 非法尺寸,跳过渲染 \(size)") + return + } + guard let drawable = view.currentDrawable, + let commandBuffer = commandQueue.makeCommandBuffer(), + let pixelBuffer = currentPixelBuffer else { + return + } + + let drawableSize = view.drawableSize + guard drawableSize.width > 0, drawableSize.height > 0 else { return } + + // 加方向修正:顺时针旋转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) { + // No-op: Handle size change if needed + } + + func display(pixelBuffer: CVPixelBuffer) { + self.currentPixelBuffer = pixelBuffer + //print("display") + //刷新 + } } -- Gitblit v1.9.1