Post

Replies

Boosts

Views

Activity

Reply to Execution time profiling of Metal compute kernels.
For profiling of your GPU pipeline, you have Metal System Trace in Instruments: https://developer.apple.com/documentation/metal/performance_tuning/using_metal_system_trace_in_instruments_to_profile_your_app For profiling of the shaders themselves, along with metrics about what is limiting their speed, you'll want to use GPU frame capture in Xcode: https://developer.apple.com/documentation/metal/debugging_tools Note that GPU frame capture can be triggered manually from Xcode when you have frames displayed, but in your case you can also use MTLCaptureManager in your code to start & stop this capture around your compute workload. So no need to have a graphic pipeline to use these tools.
Topic: Programming Languages SubTopic: Swift Tags:
Jun ’22
Reply to WKWebView offscreen rendering
I'm not sure everything will help, and I don't know for the WebKit offscreen rendering, but here are at least three points I can mention: Don't take iPhone simulator as a reference for your benchmark, use a real device Being on iPhone you can take advantage of the unified memory architecture and create textures without doing any copy, if the source data is properly allocated and aligned. In particular see https://developer.apple.com/documentation/metal/mtldevice/1433382-makebuffer and https://developer.apple.com/documentation/metal/mtlbuffer/1613852-maketexture. This means that the CGImage buffers in which you render to must have been allocated by you, following above constraints, and that the CGImage must only wrap your pointers, not copy your data to its own buffers (I'm not sure if CGImage can do that, so you might need to render into something else than a CGImage). If the size of the texture doesn't change, you can reuse the texture but make sure it's not used by Metal while you write to it: either you wait for MTLCommandBuffer to complete, or you create several buffers/textures that you reuse over time to account for triple buffering of your rendering.
Topic: Graphics & Games SubTopic: General Tags:
Jul ’22
Reply to Using Texture in Vertex Shader Error
How did you create the MTLTexture object? It says that it has a null depth. A 2D texture is expected to have a depth of 1. See https://developer.apple.com/documentation/metal/mtltexturedescriptor/1516298-depth However I would expect this kind of error to be caught by Metal API Validation, did you disable it? https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early
Topic: Graphics & Games SubTopic: General Tags:
Oct ’22
Reply to DRHT > error > MTLTextureDescriptor
Look for "Maximum 2D texture width and height" in https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf You can check the GPUFamily through MTLDevice API. As for how to workaround this limitation, I guess you only have two choices: use a smaller texture size use several textures and display them next to each other like tiles
Topic: Graphics & Games SubTopic: General Tags:
Dec ’22
Reply to Draw `MTLTexture` to `CAMetalLayer`
1 CAMetalLayer provides MTLTexture objects through -[CAMetalLayer nextDrawable] as you noticed. By default these MTLTexture are created with MTLTextureUsageRenderTarget only as usage flag, so you can only write to them through a render pipeline. This might be what you need anyway as this allows easily applying some transform to your input texture while rendering it into the drawable texture. In case you can guarantee that your RGBA data width and height will always match the size of the drawable texture, and you don't need to apply any transformation, things can be a bit simpler: you can set CAMetalLayer.framebufferOnly property to false so that the provided textures also become writable, which means that you can copy from your own (with shared or managed MTLStorageMode) MTLTexture to the drawable texture with a simple blit command instead of render command, which would remove the need for a custom shader. So the pipeline would look as follow: At init: create 3 staging textures with shared/managed storage mode At each frame: pick current staging texture and fill it with the contents rendered by Skia ask for the drawable texture schedule blit from your staging texture to your drawable texture commit increase staging texture index One thing I don't know is the MTLStorageMode of the drawable texture: in case it's already shared/managed, you don't need the staging texture and can directly fill the drawable texture instead of going through a staging texture fill + blit command. Bonus: as an additional optimization and in case drawable texture isn't shared/managed, if you detect that your MTLDevice is an Apple one, you don't need to render with Skia to some buffer before filling the MTLTexture: you can render with Skia directly into the MTLTexture. To do that: create MTLBuffer objects of the appropriate size with shared storage mode, use -[MTLBuffer newTextureWithDescriptor:offset:bytesPerRow:] to create each staging texture from them. Now if you render with Skia into MTLBuffer.contents, this will be directly available when you use the MTLTexture for your render or blit command. Just don't forget to use -[MTLBuffer didModifyRange:] after writing to MTLBuffer.contents. 2 Just from above sample code I don't know, because the only shown render pass is using drawable.texture, and the drawable would already properly configure the texture. 0x01 is MTLTextureUsageShaderRead so you might have another render pipeline somewhere trying to render in a texture with that usage. When you get this error, I assume that the debugger shows the callstack for the command buffer being submitted that has this issue. 3 I suppose that you mean "when is the GPU done with using the texture that was filled with data from Skia" ? In that case the answer is: when the command buffer that references that texture has completed (you can know it through -[MTLCommandBuffer addCompletedHandler:]). Before that it's not safe to fill again the texture with new data. That's why in above pipeline I'm using 3 staging textures: this way you can continue filling textures while the GPU is using the previously filled ones. I picked number 3 because that's the maximum for CAMetalerLayer.maximumDrawableCount, so you can't have more than 3 staging textures needed at a time. By the way this means that your current usage of _textureMutex is not useful as is and also doesn't prevent the GPU from reading the texture while you write to it for next frame scheduling.
Topic: Graphics & Games SubTopic: General Tags:
Dec ’22
Reply to CAMetalLayer.nextDrawable() is very time-consuming, take 5ms-12ms
How did you measure that? nextDrawable() may block if previously requested drawable are still being used, which means that you're asking too much from the GPU and it's not able to give back the drawables quickly enough. You should first profile with Metal System Trace in Instruments: https://developer.apple.com/documentation/metal/performance_tuning/using_metal_system_trace_in_instruments_to_profile_your_app This will show when nextDrawable is blocked.
Topic: Graphics & Games SubTopic: General Tags:
Dec ’22
Reply to CAMetalLayer.nextDrawable() is very time-consuming, take 5ms-12ms
I tried a similar way with MTKView as I'm more used to it. class ViewController: UIViewController, MTKViewDelegate {     var mtkView: MTKView!          override func viewDidLoad() {         super.viewDidLoad()         mtkView = MTKView(frame: view.bounds, device: MTLCreateSystemDefaultDevice()!)         mtkView.preferredFramesPerSecond = 120         mtkView.autoResizeDrawable = true         mtkView.delegate = self         mtkView.translatesAutoresizingMaskIntoConstraints = false         view.addSubview(mtkView)                  NSLayoutConstraint.activate([             mtkView.leftAnchor.constraint(equalTo: view.leftAnchor),             mtkView.rightAnchor.constraint(equalTo: view.rightAnchor),             mtkView.topAnchor.constraint(equalTo: view.topAnchor),             mtkView.bottomAnchor.constraint(equalTo: view.bottomAnchor),         ])     }          func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}          func draw(in view: MTKView) {         let startTime = CACurrentMediaTime()         let drawable = view.currentDrawable         let timeUsed = CACurrentMediaTime() - startTime         if (timeUsed > 0.003) {             print("CAMetalLayer.nextDrawable take much time!! -> \(String(format: "%.2f", timeUsed * 1000)) ms")         }                  guard let drawable else {             print("no drawable available")             return         }         drawable.present()     } } and it gives similar logs. However, looking at the profiling trace I don't think there's an issue at all: You can see with "LCD" line that surface is regularly displayed every 16ms, and with "Time Profiler" line that CPU isn't busy. This shows that getting the current/next drawable is not slow but is just blocking because it's too early. My understanding is that the draw() method (or in your case the onDisplayLink() method) is called "too early". In fact it's not really too early: it's a bit ahead of time to let you perform some work in advance before you actually need the drawable. This is described in more details there: https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html
Topic: Graphics & Games SubTopic: General Tags:
Dec ’22
Reply to Xcode lacks syntax highlighting in editor for .metal files
blue reference folder As I understand you got this by adding the directory in your project and choosing "Create folder reference" rather than "Create groups". When doing this, the folder is added in the project hierarchy for easy access from Xcode but is not part of any target, not indexed (so only very basic autocompletion) and consequently lacks highlighting. Unless you make your files belong to a target (thus choosing "Create groups" when adding the folder) I guess you'll only have this limited experience.
Mar ’23
Reply to using xcrun to compile .metal shader
I think you're trying to over-specify it. When building Metal shaders from Xcode 14.2 there is no "-std" or "-mios-version-min". Instead there is just "-target air64-apple-ios16.2" where 16.2 should be replaced by your iOS deployment target. And this will automatically enable the corresponding available Metal language version. You can add this to one of your shaders and see which warnings get generated: #if __METAL_VERSION__ >= 200 #warning Metal 2.0 #endif #if __METAL_VERSION__ >= 240 #warning Metal 2.4 #endif #if __METAL_VERSION__ >= 300 #warning Metal 3.0 #endif In my tries iOS 15 gives up to Metal 2.4 while setting iOS 16 target will also give Metal 3.0. And iOS 13.5 just gives Metal 2.0 (you can maybe get some intermediate versions between 2.0 and 2.4).
Mar ’23
Reply to Tile Rendering in Metal
The problem is I can't redraw the whole offscreen texture every frame while panning because for performance reasons. My idea was to implement a tile based progressive rendering technique. Before trying to go this way I would look into these 2 options: make your offscreen texture bigger, so that it is less blurry when zooming in (I guess you don't need very high zoom levels?). Pros: very simple to implement. Cons: uses more memory and rendering to that bigger texture will be slower. directly render everything to the framebuffer. I'm skeptical about you having to go through an offscreen texture. Do you really have so much to render that it's impossible to render in 16ms? Did you profile with Instruments/GPU Frame Capture to see what part is slow and whether it can be improved? Is the bottleneck the rendering or scheduling part?
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’23