Is there something wrong with how I wrote the code? What should I expect?

import PlaygroundSupport
import MetalKit

guard let device = MTLCreateSystemDefaultDevice() else {
    fatalError("GPU is not supported")
}

let frame = CGRect(x: 0, y: 0, width: 600, height: 600)
let view = MTKView(frame: frame, device: device)
view.clearColor = MTLClearColor(red: 1, green: 1, blue: 0.8, alpha: 1)

//1
let allocator = MTKMeshBufferAllocator(device: device)

//2
let mdlMesh = MDLMesh(
    sphereWithExtent: [0.75, 0.75, 0.75],
    segments: [100, 100],
    inwardNormals: false,
    geometryType: .triangles,
    allocator: allocator
)

//3
let mesh = try MTKMesh(mesh: mdlMesh, device: device)

guard let commandQueue = device.makeCommandQueue() else {
    fatalError("Could not create a command queue")
}

let shader = """
#include <metal_stdlib>
using namespace metal;

struct VertexIn {
    float4 position [[attribute(0)]];
};

vertex float4 vertex_main(const VertexIn vertex_in [[stage_in]]) {
    return vertex_in.position;
}

fragment float4 fragment_main() {
    return float4(1, 0, 0, 1);
}
"""

let library = try device.makeLibrary(source: shader, options: nil)
let vertexFunction = library.makeFunction(name: "vertex_main")
let fragmentFunction = library.makeFunction(name: "fragment_main")

let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction

pipelineDescriptor.vertexDescriptor = MTKMetalVertexDescriptorFromModelIO(mesh.vertexDescriptor)

let pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDescriptor)

//1
guard let commandBuffer = commandQueue.makeCommandBuffer(),
    // 2
    let renderPassDescriptor = view.currentRenderPassDescriptor,
    // 3
    let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
else { fatalError() }

renderEncoder.setRenderPipelineState(pipelineState)

renderEncoder.setVertexBuffer(mesh.vertexBuffers[0].buffer, offset: 0, index: 0)

guard let submesh = mesh.submeshes.first else {
    fatalError()
}

renderEncoder.drawIndexedPrimitives(type: .triangle, indexCount: submesh.indexCount, indexType: submesh.indexType, indexBuffer: submesh.indexBuffer.buffer, indexBufferOffset: 0)

// 1
renderEncoder.endEncoding()

// 2
guard let drawable = view.currentDrawable else {
    fatalError()
}

//3
commandBuffer.present(drawable)
commandBuffer.commit()

PlaygroundPage.current.liveView = view

I expected the red circle inside a cream coloured square found in “1. Hello, Metal!”.

Instead I got this:

Thank you, @smihail, for posting here. Other people may have the same problem and it’s easier to find answers here than in Discord.

You’ll be happy to hear that your code is actually working! You just can’t see the output. What you are seeing is the Playground’s Results values for every line of code executed.

Choose Editor → Live View and you’ll see the red sphere. Or click the icon at the top right as indicated in the pic.

I hope this fixes your problem so that you can continue on the journey!

1 Like

How do I hide the Results View aka the middle panel?

I don’t think you can hide it all the way, but I could be wrong. I can resize mine to be much smaller by dragging the left side of the Results View when the cursor changes shape.

I couldn’t capture the screen with the cursor shape change, but that’s where my cursor was to drag the view smaller.

1 Like

Btw Xcode 26 is different. You either see Results or Live View:

1 Like