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 |  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