google / filament

Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WebGL2
https://google.github.io/filament/
Apache License 2.0
17.58k stars 1.86k forks source link

Segfaults with Minimal Resize Example #7454

Closed jwinarske closed 2 months ago

jwinarske commented 8 months ago

Discussed in https://github.com/google/filament/discussions/7450

Originally posted by **jwinarske** December 21, 2023 I'm trying to understand the interaction required for resizing. This is modified example from other discussion that runs on Wayland, and compiles against the system SDL2. What am I missing on the resize? Something is missing. Also it takes a good 30 second for the window to show up, while the console is spammed with warning messages. This is a debug build. ``` #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct { struct wl_display* display; struct wl_surface* surface; uint32_t width; uint32_t height; } native_window; volatile uint32_t gWidth, gHeight; static int OnResize(void* data, SDL_Event* event) { if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) { SDL_Window* win = SDL_GetWindowFromID(event->window.windowID); if (win == (SDL_Window*)data) { SDL_GetWindowSizeInPixels(win, (int*)&gWidth, (int*)&gHeight); } } return 0; } void* getNativeWindow(SDL_Window* sdlWindow) { SDL_SysWMinfo wmi; SDL_VERSION(&wmi.version); SDL_GetWindowWMInfo(sdlWindow, &wmi); if (wmi.subsystem == SDL_SYSWM_X11) { auto win = (Window)wmi.info.x11.window; return (void*)win; } else if (wmi.subsystem == SDL_SYSWM_WAYLAND) { // The default Wayland swap chain extent is {0,0} // hence having to set the size SDL_GetWindowSizeInPixels(sdlWindow, (int*)&gWidth, (int*)&gHeight); // requires static native_window = {wmi.info.wl.display, wmi.info.wl.surface, gWidth, gHeight}; return (void*)&native_window; } else { std::cout << "Unknown SDL subsystem"; return nullptr; } } SDL_Window* createWindow() { const uint32_t windowFlags = SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; SDL_Window* win = SDL_CreateWindow("Hello Filament!", 100, 100, 600, 400, windowFlags); if (win == nullptr) { std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl; SDL_Quit(); return nullptr; } SDL_AddEventWatch(OnResize, win); return win; } int main() { SDL_Init(SDL_INIT_VIDEO); using namespace filament; using namespace math; using namespace utils; static constexpr uint32_t indices[] = {0, 1, 2, 2, 3, 0}; static constexpr math::float3 vertices[] = { {-10, 0, -10}, {-10, 0, 10}, {10, 0, 10}, {10, 0, -10}, }; short4 tbn = math::packSnorm16( mat3f::packTangentFrame(math::mat3f{float3{1.0f, 0.0f, 0.0f}, float3{0.0f, 0.0f, 1.0f}, float3{0.0f, 1.0f, 0.0f}}) .xyzw); const static math::short4 normals[]{tbn, tbn, tbn, tbn}; SDL_Window* window = createWindow(); Engine* engine = Engine::create(filament::backend::Backend::VULKAN); SwapChain* swapChain = engine->createSwapChain(getNativeWindow(window)); Renderer* renderer = engine->createRenderer(); auto cameraEntity = EntityManager::get().create(); Camera* camera = engine->createCamera(cameraEntity); View* view = engine->createView(); Scene* scene = engine->createScene(); view->setCamera(camera); // SDL_GetWindowSize() to query the client area's size in screen coordinates, // and SDL_GL_GetDrawableSize() or SDL_GetRendererOutputSize() to query the // drawable size in pixels. Note that when this flag is set, the drawable size // can vary after the window is created and should be queried after major // window events such as when the window is resized or moved between displays. // If the window is set fullscreen, the width and height parameters `w` and // `h` will not be used. However, invalid size parameters (e.g. too large) may // still fail. Window size is actually limited to 16384 x 16384 for all // platforms at window creation. Compute the "virtual pixels to physical // pixels" scale factor that the platform uses for UI elements. int virtualWidth, virtualHeight; SDL_GetWindowSize(window, &virtualWidth, &virtualHeight); float dpiScaleX = (float)gWidth / (float)virtualWidth; float dpiScaleY = (float)gHeight / (float)virtualHeight; std::cout << "dpi Scale X: " << dpiScaleX << std::endl; std::cout << "dpi Scale Y: " << dpiScaleY << std::endl; camera->lookAt(float3(0, 50.5f, 0), float3(0, 0, 0), float3(1.f, 0, 0)); camera->setProjection(45.0, double(gWidth) / gHeight, 0.1, 50, Camera::Fov::VERTICAL); view->setViewport({0, 0, gWidth, gHeight}); view->setScene(scene); VertexBuffer* vertexBuffer = VertexBuffer::Builder() .vertexCount(4) .bufferCount(2) .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3) .attribute(VertexAttribute::TANGENTS, 1, VertexBuffer::AttributeType::SHORT4) .normalized(VertexAttribute::TANGENTS) .build(*engine); vertexBuffer->setBufferAt( *engine, 0, VertexBuffer::BufferDescriptor( vertices, vertexBuffer->getVertexCount() * sizeof(vertices[0]))); vertexBuffer->setBufferAt( *engine, 1, VertexBuffer::BufferDescriptor( normals, vertexBuffer->getVertexCount() * sizeof(normals[0]))); IndexBuffer* indexBuffer = IndexBuffer::Builder().indexCount(6).build(*engine); indexBuffer->setBuffer( *engine, IndexBuffer::BufferDescriptor( indices, indexBuffer->getIndexCount() * sizeof(uint32_t))); auto skybox = Skybox::Builder().color({0.5, 0.5, 0.5, 1.0}).build(*engine); scene->setSkybox(skybox); filamat::MaterialBuilder::init(); filamat::MaterialBuilder builder; builder.name("Some material") .material( " void material(inout MaterialInputs material) {\n" " prepareMaterial(material);\n" " material.baseColor.rgb = materialParams.baseColor;\n" " material.metallic = materialParams.metallic;\n" " material.roughness = materialParams.roughness;\n" " material.reflectance = materialParams.reflectance;\n" " }") .parameter("baseColor", filament::backend::UniformType::FLOAT3) .parameter("metallic", filament::backend::UniformType::FLOAT) .parameter("roughness", filament::backend::UniformType::FLOAT) .parameter("reflectance", filament::backend::UniformType::FLOAT) .shading(filamat::MaterialBuilder::Shading::LIT) .targetApi(filamat::MaterialBuilder::TargetApi::ALL) .platform(filamat::MaterialBuilder::Platform::ALL); filamat::Package package = builder.build(engine->getJobSystem()); Material* material = Material::Builder() .package(package.getData(), package.getSize()) .build(*engine); material->setDefaultParameter("baseColor", RgbType::LINEAR, float3{0, 1, 0}); material->setDefaultParameter("metallic", 0.0f); material->setDefaultParameter("roughness", 0.4f); material->setDefaultParameter("reflectance", 0.5f); MaterialInstance* materialInstance = material->createInstance(); Entity renderable = EntityManager::get().create(); Entity light = EntityManager::get().create(); LightManager::Builder(LightManager::Type::SUN) .color(Color::toLinear(sRGBColor(0.98f, 0.92f, 0.89f))) .intensity(110000) .direction({0.7, -1, -0.8}) .sunAngularRadius(1.9f) .castShadows(true) .build(*engine, light); scene->addEntity(light); // build a quad RenderableManager::Builder(1) .boundingBox({{-1, -1, -1}, {1, 1, 1}}) .material(0, materialInstance) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vertexBuffer, indexBuffer, 0, 6) .culling(false) .build(*engine, renderable); scene->addEntity(renderable); volatile uint32_t prev_width = gWidth; volatile uint32_t prev_height = gHeight; bool keep_window_open = true; while (keep_window_open) { SDL_Event e; while (SDL_PollEvent(&e) > 0) { switch (e.type) { case SDL_QUIT: keep_window_open = false; break; } if (prev_width != gWidth || prev_height != gHeight) { prev_width = gWidth; prev_height = gHeight; engine->destroy(swapChain); swapChain = engine->createSwapChain(getNativeWindow(window)); view->setViewport({0, 0, gWidth, gHeight}); camera->setProjection(45.0, double(gWidth) / gHeight, 0.1, 50, Camera::Fov::VERTICAL); } // beginFrame() returns false if we need to skip a frame if (renderer->beginFrame(swapChain)) { // for each View renderer->render(view); renderer->endFrame(); } SDL_UpdateWindowSurface(window); SDL_Delay(16); } } engine->destroy(scene); engine->destroy(view); engine->destroy(cameraEntity); engine->destroy(light); engine->destroy(skybox); engine->destroy(renderable); engine->destroy(indexBuffer); engine->destroy(vertexBuffer); engine->destroy(materialInstance); engine->destroy(material); engine->destroy(renderer); engine->destroy(swapChain); Engine::destroy(engine); SDL_Quit(); return 0; } ```
jwinarske commented 8 months ago

log snippet of valid run

/mnt/raid10/stargate/ivi-homescreen/cmake-build-debug-clang/plugins/filament_view/simple
libdecor-gtk-WARNING: Failed to initialize GTK
Failed to load plugin 'libdecor-gtk.so': failed to init
FEngine (64 bits) created at 0x1e37780 (threading is enabled)
FEngine resolved backend: Vulkan
Vulkan device driver: radv Mesa 23.1.9
Selected physical device 'AMD Radeon Graphics (RADV RAPHAEL_MENDOCINO)' from 2 physical devices. (vendor 0x1002, device 0x164e, driver 0x5c01009, api 1.3)
Backend feature level: 1
FEngine feature level: 1
WARNING: :0:0:0: The function '%41 = OpFunction %2 None %37' could not be inlined because the return instruction is not at the end of the function. This could be fixed by running merge-return before inlining.
WARNING: :0:0:0: The function '%91 = OpFunction %6 None %89' could not be inlined because the return instruction is not at the end of the function. This could be fixed by running merge-return before inlining.
WARNING: :0:0:0: The function '%91 = OpFunction %6 None %89' could not be inlined because the return instruction is not at the end of the function. This could be fixed by running merge-return before inlining.
... lots more warnings (removed for brevity)
vkCreateSwapchain: 1200x800, VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, swapchain-size=5, identity-transform=true, depth=VK_FORMAT_D32_SFLOAT
Renderer: Commands High watermark 0 KiB (0%), 6 commands, 64 bytes/command
CircularBuffer: High watermark 18 KiB (0%)
FEngine::mHeapAllocator arena: High watermark 189 KiB
jwinarske commented 8 months ago

Running near tip of tree main: 0e9b2eda0aaeba3e69251616b5e849103c124a62

jwinarske commented 8 months ago

Behavior is different running on release. On debug it takes about two maximize/restore, and with release it takes ~7 maximize/restore then hitting this stack trace:

[libc.so.6] __pthread_kill_implementation 0x00007ffff7d0f834
[libc.so.6] raise 0x00007ffff7cbd8ee
[libc.so.6] abort 0x00007ffff7ca58ff
[libc++abi.so.1] abort_message 0x00007ffff7e87b0f
[libc++abi.so.1] demangling_terminate_handler() 0x00007ffff7e70e8f
[libc++abi.so.1] std::__terminate(void (*)()) 0x00007ffff7e869aa
[libc++abi.so.1] std::terminate() 0x00007ffff7e86924
[simple] __clang_call_terminate 0x00000000004d47ce
[simple] filament::backend::ConcreteDispatcher<filament::backend::VulkanDriver>::commit(filament::backend::Driver&, filament::backend::CommandBase*, long*) 0x000000000090af1b
[simple] std::__1::__function::__func<filament::backend::CommandStream::execute(void*)::$_0, std::__1::allocator<filament::backend::CommandStream::execute(void*)::$_0>, void ()>::operator()() [clone .llvm.9022111094664947753] 0x00000000008f1b4b
[simple] filament::backend::Driver::execute(std::__1::function<void ()> const&) 0x0000000000938910
[simple] filament::backend::CommandStream::execute(void*) 0x00000000008f190c
[simple] filament::FEngine::execute() 0x00000000008d0e60
[simple] filament::FEngine::loop() 0x00000000008c7990
[simple] void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (filament::FEngine::*)(), filament::FEngine*> >(void*) 0x00000000008d251b
[libc.so.6] start_thread 0x00007ffff7d0d897
[libc.so.6] clone3 0x00007ffff7d946fc
jwinarske commented 7 months ago

CMake used to build it:

set(CONTEXT_COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++> $<$<COMPILE_LANGUAGE:CXX>:-isystem${LLVM_ROOT}/include/c++/v1/>)

#
# Toolchain IPO/LTO support
#
if (ENABLE_LTO)
    cmake_policy(SET CMP0069 NEW)
    include(CheckIPOSupported)
    check_ipo_supported(
            RESULT IPO_SUPPORT_RESULT
            OUTPUT IPO_SUPPORT_OUTPUT
            LANGUAGES C CXX
    )
endif ()

add_library(filament INTERFACE)
target_include_directories(filament INTERFACE ${FILAMENT_INCLUDE_DIR})
target_link_directories(filament INTERFACE ${FILAMENT_LINK_LIBRARIES_DIR})
target_link_libraries(filament INTERFACE
        libbackend.a
        libbluevk.a
        libdracodec.a
        libfilamat.a
        libfilameshio.a
        libgltfio_core.a
        libimage.a
        libshaders.a
        libuberarchive.a
        libviewer.a
        libbasis_transcoder.a
        libcamutils.a
        libfilabridge.a
        libfilament.a
        libgeometry.a
        libibl.a
        libimageio.a
        libmeshoptimizer.a
        libsmol-v.a
        libuberzlib.a
        libvkshaders.a
        libcivetweb.a
        libtinyexr.a
        libfilaflat.a
        libfilament-iblprefilter.a
        libgltfio.a
        libibl-lite.a
        libktxreader.a
        libmikktspace.a
        libpng.a
        libstb.a
        libutils.a
        libzstd.a

        z
        Threads::Threads
)

set(CMAKE_THREAD_PREFER_PTHREAD ON)
include(FindThreads)

#
# Simple Example
#
pkg_check_modules(SDL2 IMPORTED_TARGET sdl2)
if (SDL2_FOUND)
    add_executable(simple test/simple.cc)
    target_link_libraries(simple PUBLIC
            PkgConfig::SDL2
            filament
            ${FILAMENT_LINK_LIBRARIES_DIR}/../../../../third_party/spirv-tools/source/opt/libSPIRV-Tools-opt.a
            ${FILAMENT_LINK_LIBRARIES_DIR}/../../../../third_party/spirv-cross/tnt/libspirv-cross-msl.a
    )
    target_compile_options(simple PRIVATE ${CONTEXT_COMPILE_OPTIONS})
    target_link_options(simple PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fuse-ld=lld -lc++ -lc++abi -lc -lm -v>)

    if (IPO_SUPPORT_RESULT)
        set_property(TARGET simple PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
    endif ()
endif ()
jwinarske commented 2 months ago

I just rolled to v1.52.3 from v1.49.2 and have confirmed this issue is now resolved. No more crashing on resize. Thank you!