0.1 C
New York
Sunday, March 9, 2025

ios – Methods to correctly cross a Metallic layer from SwiftUI MTKView to C++ to be used with metal-cpp?


I am at the moment porting a videogame console emulator to iOS and I am attempting to make the renderer (examined on MacOS) work on iOS as properly.

The emulator core is written in C++ and makes use of metal-cpp for rendering, whereas the iOS frontend is written in Swift with SwiftUI. I’ve an Goal-C++ bridging header for bridging the Swift and C++ sides.

On the Swift aspect, I create an MTKView. Contained in the MTKView delegate, I run the emulator for 1 video body and cross it the view’s backing layer for it to render the ultimate output picture with. The emulator runs and returns, however when it returns I get a crash in Swift land (callstack hooked up beneath), inside objc_release, which signifies I am doing one thing flawed with reminiscence administration.

My bridging interface (ios_driver.h):

#pragma as soon as
#embody 
#embody 

void iosCreateEmulator();
void iosRunFrame(CAMetalLayer* layer);

Bridge implementation (ios_driver.mm):

#import 

extern "C" {
#embody "ios_driver.h"
}

<...>

#outline IOS_EXPORT extern "C" __attribute__((visibility("default")))

std::unique_ptr emulator = nullptr;
IOS_EXPORT void iosCreateEmulator() { ... }

// Runs 1 video body of the emulator and 
IOS_EXPORT void iosRunFrame(CAMetalLayer* layer) {
    void* layerBridged = (__bridge void*)layer;

    // Go the CAMetalLayer to the emulator
    emulator->getRenderer()->setMTKLayer(layerBridged);
    // Runs the emulator for 1 body and renders the output picture utilizing our layer
    emulator->runFrame();
}

My MTKView delegate:

class Renderer: NSObject, MTKViewDelegate {
    var dad or mum: ContentView
    var gadget: MTLDevice!
    
    init(_ dad or mum: ContentView) {
        self.dad or mum = dad or mum
        if let gadget = MTLCreateSystemDefaultDevice() {
            self.gadget = gadget
        }
        
        tremendous.init()
    }
    
    func mtkView(_ view: MTKView, drawableSizeWillChange dimension: CGSize) {}
    
    func draw(in view: MTKView) {
        var metalLayer = view.layer as! CAMetalLayer
        // Run the emulator for 1 body & show the output picture
        iosRunFrame(metalLayer)
    }
}

Lastly, the emulator’s render perform that interacts with the layer:

void RendererMTL::setMTKLayer(void* layer) {
    metalLayer = (CA::MetalLayer*)layer;
}

void RendererMTL::show() {
    CA::MetalDrawable* drawable = metalLayer->nextDrawable();
    if (!drawable) {
        return;
    }

    MTL::Texture* texture = drawable->texture();
   
}

That is the Swift callstack on the time of the crash:

To my understanding, I should not be violating ARC guidelines as my bridging header makes use of CAMetalLayer* as a substitute of void* and Swift will mechanically account for ARC when passing CoreFoundation objects to Goal-C. Nevertheless I haven’t got every other thought as to what is perhaps inflicting this. I have been attempting to debug this code for a few days with out a lot success.

In case you want extra data, the emulator code can also be on Github

Metallic renderer: https://github.com/wheremyfoodat/Panda3DS/blob/ios/src/core/renderer_mtl/renderer_mtl.cpp#L58-L68

Bridge implementation: https://github.com/wheremyfoodat/Panda3DS/blob/ios/src/ios_driver.mm

Bridging header: https://github.com/wheremyfoodat/Panda3DS/blob/ios/embody/ios_driver.h

Different issues I’ve tried:

  • I used to be initially utilizing a void* as a substitute of a CAMetalLayer* within the bridging interface however that crashed in the same manner & made reminiscence administration much more complicated so I dropped it.

  • Changing iosRunFrame’s code with only a printf would not result in a crash, the C++ aspect returns and the app retains operating. Nevertheless, that is not very useful since I can not see something…

  • Operating the emulator with out rendering (utilizing its null renderer) additionally works. I get the right print messages within the XCode terminal & I can hear the sport audio.

  • I’ve tried a number of different methods of passing the issues I must render from Swift to C++, to no avail, all of them crash in objc_release in a similar way (I’ve tried passing a MetalDrawable* as a substitute of the CAMetalLayer itself for instance)

Any assistance is greater than appreciated. Thanks in your time prematurely.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles