Skip to content

Commit

Permalink
add error logging on all guards for hydra+metal.
Browse files Browse the repository at this point in the history
Signed-off-by: furby™ <devs@wabi.foundation>
  • Loading branch information
furby-tm committed Dec 29, 2024
1 parent 9126efe commit 6a45a36
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 80 deletions.
2 changes: 1 addition & 1 deletion Sources/UsdView/Hydra/Hydra+RenderEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
132 changes: 53 additions & 79 deletions Sources/UsdView/Hydra/MTL/Hydra+MTLRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -71,49 +93,51 @@ 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
}

/// copies the texture to the view with a shader.
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
Expand All @@ -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)

0 comments on commit 6a45a36

Please sign in to comment.