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 |  127 ++++++++++++++++++++++++++----------------
 1 files changed, 79 insertions(+), 48 deletions(-)

diff --git a/LiveProject/tool/MetalRenderer.swift b/LiveProject/tool/MetalRenderer.swift
index a2aa4ba..61bd769 100644
--- a/LiveProject/tool/MetalRenderer.swift
+++ b/LiveProject/tool/MetalRenderer.swift
@@ -4,68 +4,99 @@
 //  渲染工具
 //  Created by 倪路朋 on 6/26/25.
 //
+import Foundation
+import Metal
 import MetalKit
+import AVFoundation
 
 class MetalRenderer: NSObject, MTKViewDelegate {
-    private var device: MTLDevice!
-    private var commandQueue: MTLCommandQueue!
-    private var textureCache: CVMetalTextureCache!
+    private let device: MTLDevice
+    private let commandQueue: MTLCommandQueue
+    private let ciContext: CIContext
+
     private var currentPixelBuffer: CVPixelBuffer?
+    private let textureCache: CVMetalTextureCache
 
-    func setup(view: MTKView) {
-        self.device = view.device
-        self.commandQueue = device.makeCommandQueue()
-        CVMetalTextureCacheCreate(nil, nil, device, nil, &textureCache)
+    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")
     }
-
-    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 }
+        let size = view.drawableSize
+        //print("🧾 drawableSize = \(size)")
 
-        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)")
+        if !size.width.isFinite || !size.height.isFinite || size.width <= 0 || size.height <= 0 {
+            print("❌ 非法尺寸,跳过渲染 \(size)")
             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),
+        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,
-                         destinationSlice: 0,
-                         destinationLevel: 0,
-                         destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0))
-        blitEncoder.endEncoding()
+                         commandBuffer: commandBuffer,
+                         bounds: CGRect(origin: .zero, size: drawableSize),
+                         colorSpace: CGColorSpaceCreateDeviceRGB())
 
         commandBuffer.present(drawable)
         commandBuffer.commit()
-        print("绘制画面")
+        //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