diff --git a/Sources/UsdView/Hydra/Hydra+RenderEngine.swift b/Sources/UsdView/Hydra/Hydra+RenderEngine.swift index 29653a3b4..78960cee7 100644 --- a/Sources/UsdView/Hydra/Hydra+RenderEngine.swift +++ b/Sources/UsdView/Hydra/Hydra+RenderEngine.swift @@ -57,7 +57,7 @@ public enum Hydra // Viewport setup. let viewport = Gf.Vec4d(0, 0, viewSize.width, viewSize.height) engine.pointee.SetRenderViewport(viewport) - engine.pointee.SetWindowPolicy(Pixar.CameraUtilConformWindowPolicy.init(0)) + engine.pointee.SetWindowPolicy(Pixar.CameraUtilConformWindowPolicy(0)) var params = UsdImagingGL.RenderParams() params.frame = Usd.TimeCode(timeCode) diff --git a/Sources/UsdView/Hydra/MTL/Hydra+MTLRenderer.swift b/Sources/UsdView/Hydra/MTL/Hydra+MTLRenderer.swift index 4a970b665..3929c16d1 100644 --- a/Sources/UsdView/Hydra/MTL/Hydra+MTLRenderer.swift +++ b/Sources/UsdView/Hydra/MTL/Hydra+MTLRenderer.swift @@ -22,7 +22,6 @@ import PixarUSD { private let device: MTLDevice private var hydra: Hydra.RenderEngine? - /// private let commandQueue: MTLCommandQueue private var pipelineState: MTLRenderPipelineState? private var inFlightSemaphore = DispatchSemaphore(value: 1) @@ -37,27 +36,50 @@ import PixarUSD { self.device = device - // guard let commandQueue = device.makeCommandQueue() - // else { return nil } - - // self.commandQueue = commandQueue super.init() - loadMetal() + setupPipeline() } private func setupPipeline() { - let library = try! device.makeDefaultLibrary(bundle: .usdview) - let vertexFunction = library.makeFunction(name: "vertex_main") - let fragmentFunction = library.makeFunction(name: "fragment_main") + do + { + let defaultLibrary = try device.makeDefaultLibrary(bundle: .usdview) + + guard let vertexFunction = defaultLibrary.makeFunction(name: "vtxBlit") + else { Msg.logger.error("HYDRA: Failed to create vertex function."); return } + + guard let fragmentFunction = defaultLibrary.makeFunction(name: "fragBlitLinear") + else { Msg.logger.error("HYDRA: Failed to create fragment function."); return } - let pipelineDescriptor = MTLRenderPipelineDescriptor() - pipelineDescriptor.vertexFunction = vertexFunction - pipelineDescriptor.fragmentFunction = fragmentFunction - pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm + // set up the pipeline state descriptor. + let pipelineStateDescriptor = MTLRenderPipelineDescriptor() + pipelineStateDescriptor.rasterSampleCount = 1 + pipelineStateDescriptor.vertexFunction = vertexFunction + pipelineStateDescriptor.fragmentFunction = fragmentFunction + pipelineStateDescriptor.depthAttachmentPixelFormat = .invalid + + // configure the color attachment for blending. + if let colorAttachment = pipelineStateDescriptor.colorAttachments[0] + { + colorAttachment.pixelFormat = .bgra8Unorm + colorAttachment.isBlendingEnabled = true + colorAttachment.rgbBlendOperation = .add + colorAttachment.alphaBlendOperation = .add + colorAttachment.sourceRGBBlendFactor = .one + colorAttachment.sourceAlphaBlendFactor = .one + colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha + colorAttachment.destinationAlphaBlendFactor = .zero + } - pipelineState = try? device.makeRenderPipelineState(descriptor: pipelineDescriptor) + // create the pipeline state object. + pipelineState = try device.makeRenderPipelineState(descriptor: pipelineStateDescriptor) + } + catch + { + Msg.logger.error("HYDRA: Failed to create pipeline state: \(error.localizedDescription)") + } } public func mtkView(_: MTKView, drawableSizeWillChange _: CGSize) @@ -71,29 +93,37 @@ import PixarUSD /// draw the scene, and blit the result to the view. func drawFrame(in view: MTKView, timeCode: Double) -> Bool { - guard let hgi = hydra?.getHgi() else { return false } + guard let hgi = hydra?.getHgi() + else { Msg.logger.error("HYDRA: Failed to retrieve hgi."); return false } // start the next frame. _ = inFlightSemaphore.wait(timeout: .distantFuture) defer { inFlightSemaphore.signal() } + /* + * ---------------------------------------------------------------- */ + hgi.pointee.StartFrame() - // draw the scene using Hydra, and recast the result to a MTLTexture. + // draw the scene using hydra, and recast the result to a MTLTexture. let viewSize = view.drawableSize guard let hgiTexture = hydra?.render(at: timeCode, viewSize: viewSize), let metalTexture = hgiTexture.GetId() as? MTLTexture, let commandBuffer = hgi.pointee.GetPrimaryCommandBuffer() - else { return false } + else { Msg.logger.error("HYDRA: Failed to draw the scene."); return false } // copy the rendered texture to the view. blitToView(view, commandBuffer: commandBuffer, texture: metalTexture) - // tell Hydra to commit the command buffer and complete the work. + // tell hydra to commit the command buffer and complete the work. hgi.pointee.CommitPrimaryCommandBuffer() + hgi.pointee.EndFrame() + /* + * ---------------------------------------------------------------- */ + return true } @@ -101,19 +131,13 @@ import PixarUSD public func blitToView(_ view: MTKView, commandBuffer: MTLCommandBuffer, texture: MTLTexture) { guard let renderPassDescriptor = view.currentRenderPassDescriptor - else - { - return - } + else { Msg.logger.error("HYDRA: Failed to blit because there is no render pass descriptor for the current view."); return } - // Create a render command encoder to encode the copy command. + // create a render command encoder to encode the copy command. guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) - else - { - return - } + else { Msg.logger.error("HYDRA: Failed to create a render command encoder to blit the texture to the view."); return } - // Blit the texture to the view. + // blit the texture to the view. renderEncoder.pushDebugGroup("FinalBlit") renderEncoder.setFragmentTexture(texture, index: 0) if let pipelineState @@ -123,63 +147,13 @@ import PixarUSD renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3) renderEncoder.popDebugGroup() - // Finish encoding the copy command. + // finish encoding the copy command. renderEncoder.endEncoding() if let drawable = view.currentDrawable { commandBuffer.present(drawable) } } - - /// Prepares the Metal objects for copying to the view. - private func loadMetal() - { - do - { - let defaultLibrary = try device.makeDefaultLibrary(bundle: .usdview) - - guard let vertexFunction = defaultLibrary.makeFunction(name: "vtxBlit") - else - { - print("Failed to create vertex function.") - return - } - - guard let fragmentFunction = defaultLibrary.makeFunction(name: "fragBlitLinear") - else - { - print("Failed to create fragment function.") - return - } - - // Set up the pipeline state descriptor. - let pipelineStateDescriptor = MTLRenderPipelineDescriptor() - pipelineStateDescriptor.rasterSampleCount = 1 - pipelineStateDescriptor.vertexFunction = vertexFunction - pipelineStateDescriptor.fragmentFunction = fragmentFunction - pipelineStateDescriptor.depthAttachmentPixelFormat = .invalid - - // Configure the color attachment for blending. - if let colorAttachment = pipelineStateDescriptor.colorAttachments[0] - { - colorAttachment.pixelFormat = .bgra8Unorm - colorAttachment.isBlendingEnabled = true - colorAttachment.rgbBlendOperation = .add - colorAttachment.alphaBlendOperation = .add - colorAttachment.sourceRGBBlendFactor = .one - colorAttachment.sourceAlphaBlendFactor = .one - colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha - colorAttachment.destinationAlphaBlendFactor = .zero - } - - // Create the pipeline state object. - pipelineState = try device.makeRenderPipelineState(descriptor: pipelineStateDescriptor) - } - catch - { - print("Failed to create pipeline state: \(error.localizedDescription)") - } - } } } #endif // canImport(Metal) && !os(visionOS)