基本 ImGui 程序不渲染、内存泄漏和崩溃

问题描述 投票:0回答:1

我正在尝试使用 ImGui、GLFW 和 Metal API 创建最基本的示例程序。

这是我的代码:

// main.mm

#include <iostream>

#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_COCOA
#include <GLFW/glfw3native.h>
#include <imgui.h>
#include <backends/imgui_impl_osx.h>
#include <backends/imgui_impl_metal.h>
#include <Metal/Metal.h>
#include <QuartzCore/CAMetalLayer.h>

int main() {
    if (!glfwInit()) {
        std::cout << "Failed to init GLFW\n";
        return 1;
    }
    auto* W = glfwCreateWindow(1000, 800, "My Window", nullptr, nullptr);
    if (!W) {
        std::cout << "Failed to create window\n";
        return 1;
    }
    int width = 0, height = 0;
    glfwGetWindowSize(W, &width, &height);
    ImGui::CreateContext();
    NSWindow* NSW = glfwGetCocoaWindow(W);
    ImGui_ImplOSX_Init(NSW.contentView);
    id<MTLDevice> device = MTLCreateSystemDefaultDevice();
    ImGui_ImplMetal_Init(device);
    CAMetalLayer* layer = [[CAMetalLayer alloc] init];
    layer.device = device;
    layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
    layer.drawableSize = CGSize{ 2.0 * width, 2.0 * height };
    NSW.contentView.wantsLayer = true;
    [NSW.contentView setLayer:layer];
    id commandQueue = [device newCommandQueue];
    ImGui_ImplMetal_CreateFontsTexture(device);
    while (!glfwWindowShouldClose(W)) {
        ImGuiIO& io = ImGui::GetIO();
        io.DisplaySize = ImVec2(width, height);
        ImGui_ImplOSX_NewFrame(NSW.contentView);
        ImGui::NewFrame();
        
        // User code
        ImGui::ShowDemoWindow();
        
        id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
        MTLRenderPassDescriptor* renderPassDescriptor = [[MTLRenderPassDescriptor alloc] init];
        MTLRenderPassColorAttachmentDescriptor* caDesc = [[MTLRenderPassColorAttachmentDescriptor alloc] init];
        id<CAMetalDrawable> drawable = layer.nextDrawable;
        caDesc.texture = drawable.texture;
        caDesc.loadAction = MTLLoadActionClear;
        caDesc.storeAction = MTLStoreActionStore;
        [renderPassDescriptor.colorAttachments setObject: caDesc
                                      atIndexedSubscript: 0];
        ImGui_ImplMetal_NewFrame(renderPassDescriptor);
        
        // Rendering
        ImGui::Render();
        ImDrawData* drawData = ImGui::GetDrawData();
        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1, 0, 1, 1);
        id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
        [renderEncoder pushDebugGroup:@"Dear ImGui rendering"];
        ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder);
        [renderEncoder popDebugGroup];
        [renderEncoder endEncoding];
        // Present
        [commandBuffer presentDrawable: drawable];
        [commandBuffer commit];
        [drawable present];
        
        glfwPollEvents();
    }
    ImGui_ImplMetal_Shutdown();
    ImGui_ImplOSX_Shutdown();
}

这将创建一个我可以与之交互的窗口。但仅此而已。窗口是黑色的,程序疯狂地泄漏内存(3秒后它使用了3GB内存),它每秒绘制300到3000帧,并在一个名为

的函数中再几秒后崩溃
layer_private_present_impl(_CAMetalLayerPrivate*, CAMetalDrawable*, double, unsigned int)

我做错了什么?

cocoa glfw metal objective-c++ imgui
1个回答
0
投票

您的案例有两个问题:

  1. 代码的编写方式假设启用了自动引用计数(ARC),但在项目设置中未启用它,至少在评论中附加的链接中是这样。

  2. 您在

    @autoreleasepool { ... }
    的身体周围缺少
    while (!glfwWindowShouldClose(W))
    。如果你添加 autoreleasepool,它会起作用,有点。

需要明确的是,要修复此示例,您不需要执行 1,只需添加一个自动释放池即可。

但是你确实需要启用 ARC。您可以通过进入项目设置并启用

Objective-C Automatic Reference Counting
或启用此 Xcode 设置
CLANG_ENABLE_OBJC_ARC = NO
来完成此操作。或者你也可以传递
-fobjc-arc
编译器选项。

© www.soinside.com 2019 - 2024. All rights reserved.