#1465·tracy

Support for metal-cpp for Metal GPU Profiling

Author: spndaCreated Aug 29, 2026Updated Aug 29, 2026

The current tracy/TracyMetal.hmm expects to be used in a Objective-C++ environment. However, Apple has offered a C++ wrapper called metal-cpp which allows applications to use Metal from nearly only C++ for over two years now.

I looked into what it would take to implement this, and I think the main issue would be that the implementation for the functionality would need to be moved into a separate Objective-C++ source file since what people commonly do is just have wrappers. For example, ImGui does it like this (this is not exactly the source, but a modified excerpt to make it clear what happens):

objc
#ifndef __OBJC__
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
                                                   MTL::CommandBuffer* commandBuffer,
                                                   MTL::RenderCommandEncoder* commandEncoder);
#else
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
                                                   id<MTLCommandBuffer> commandBuffer,
                                                   id<MTLRenderCommandEncoder> commandEncoder);
#endif
objc
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
                                    MTL::CommandBuffer* commandBuffer,
                                    MTL::RenderCommandEncoder* commandEncoder)
{
    ImGui_ImplMetal_RenderDrawData(draw_data,
                                   (__bridge id<MTLCommandBuffer>)(commandBuffer),
                                   (__bridge id<MTLRenderCommandEncoder>)(commandEncoder));
}

void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
{
...
}

Meaning that the header included into the project's source files is compiled only with the metal-cpp overloads while the Objective-C++ source file compiles with both overloads and redirects the function calls.

My concern here is the current way these wrappers are implemented for the Tracy client and the fact that they are all header-only. Also, since performance is obviously a concern I don't think it is reasonable to add any large overhead to these functions. However, due to compatibility and easy-of-use I think it would still absolutely be worth it to implement this. Is it ok if the implementation is moved to the client directory? If so I'd be happy to implement this.

Furthermore (unrelated to the original issue), with Metal 4 the limitation mentioned in the User Manual is not a thing anymore, I think.

At the moment, the Metal back-end in Tracy operates differently than other GPU back-ends like Vulkan, Direct3D and OpenGL. Specifically, TracyMetalZone(name, encoderDescriptor) must be placed before the site where a command encoder is about to be created. This is because not all Apple hardware supports timestamps at command granularity, and can only provide timestamps around an entire command encoder (this accommodates for all tiers of GPU hardware on Apple platforms).

The Metal 4 command buffer has a writeTimestamp function now, see: https://developer.apple.com/documentation/metal/mtl4commandbuffer/writetimestamp(counterheap:index:). This looks to match the Vulkan behavior.