From 1d6a1a906ce2b7c3158b59bea6049172def4407c Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 3 Jun 2026 02:58:34 +0800 Subject: [PATCH 1/2] docs: plan GL runtime boundary --- .../2026-06-03-gl-runtime-boundary-plan.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 .agents/docs/2026-06-03-gl-runtime-boundary-plan.md diff --git a/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md b/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md new file mode 100644 index 0000000..cadefbe --- /dev/null +++ b/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md @@ -0,0 +1,75 @@ +# imgui-m: GL Runtime Boundary Plan + +> 状态: active +> 分支: `codex/gl-runtime-closure-imgui` +> PR: pending +> Last updated: 2026-06-03 +> 目标: 保持 ImGui module wrapper 简洁,提供可诊断的最小窗口示例,并明确 GL runtime 由 mcpp/mcpp-index 层闭合。 + +## Scope + +This repository owns the ImGui module wrapper and examples. It should prove +that consumers can write a minimal window application with module imports, but +it should not package platform OpenGL/GLX/EGL drivers. + +## Current Work + +- `examples/minimal_window/` demonstrates a module-only consumer path. +- GLFW error forwarding lets examples report the actual window creation + failure instead of silently exiting. +- README and architecture docs explain that `compat.opengl` provides headers + and registry data, not platform GL runtime libraries. + +## Implementation Plan + +- [x] Create this repository-level plan checkpoint. +- [x] Add a minimal module-only window example. +- [x] Add GLFW error accessors for backend diagnostics. +- [x] Add test coverage for exported diagnostic API presence. +- [ ] Adjust the minimal example to capture GLFW error details before cleanup + when a cleanup call could clear the last error. +- [ ] Keep README and architecture docs aligned with the final mcpp-index + package names. + - If the runtime provider lands as `compat.glvnd`, use that name. + - If the package name changes during implementation, update docs only after + the index PR settles. +- [ ] Add or update CI build-checks for `examples/minimal_window`. + - Runtime execution should stay conditional on a visible display and OpenGL + runtime. + +## Non-Goals + +- Do not bundle `libGL`, GLX/EGL, Mesa, NVIDIA, or host GPU driver files here. +- Do not hard-code host library paths in example source. +- Do not make headless CI depend on a real display. +- Do not change `compat.opengl` semantics from this repository. + +## Verification + +- [ ] `mcpp build` +- [ ] `mcpp test` +- [ ] `cd examples/basic && mcpp run` +- [ ] `cd examples/minimal_window && mcpp build` +- [ ] `cd examples/glfw_opengl3 && mcpp build` +- [ ] On a machine with working display/runtime closure: + `cd examples/minimal_window && mcpp run` + +## PR / CI / Merge Notes + +- [ ] Commit this plan as the first checkpoint on the feature branch. +- [ ] Keep current implementation checkpoint commits small. +- [ ] Open a PR with sanitized paths and no local machine details. +- [ ] Include a test plan that separates build-only CI from display-required + runtime checks. +- [ ] Wait for CI. +- [ ] Squash merge after required checks pass. + +## Cross-Repository Dependencies + +- `mcpp` must implement runtime metadata/run environment support before the + minimal window example can be expected to run without manual environment + setup. +- `mcpp-index` must express GLFW/OpenGL runtime requirements through package + metadata. +- `xim-pkgindex` is not required for this repository PR unless a released mcpp + version becomes a package-index dependency. From 0d16bbc9853d3eba57019f45c4f2511e83a41db7 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Wed, 3 Jun 2026 03:24:30 +0800 Subject: [PATCH 2/2] feat: add minimal window diagnostics --- .../2026-06-03-gl-runtime-boundary-plan.md | 18 ++--- .github/workflows/ci.yml | 5 ++ README.md | 19 ++++- docs/architecture.md | 8 +- examples/minimal_window/mcpp.toml | 11 +++ examples/minimal_window/src/main.cpp | 77 +++++++++++++++++++ src/backends/glfw.cppm | 4 + src/backends/glfw_opengl3.cppm | 4 + tests/backend_test.cpp | 4 + 9 files changed, 136 insertions(+), 14 deletions(-) create mode 100644 examples/minimal_window/mcpp.toml create mode 100644 examples/minimal_window/src/main.cpp diff --git a/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md b/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md index cadefbe..2d07d8c 100644 --- a/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md +++ b/.agents/docs/2026-06-03-gl-runtime-boundary-plan.md @@ -26,14 +26,14 @@ it should not package platform OpenGL/GLX/EGL drivers. - [x] Add a minimal module-only window example. - [x] Add GLFW error accessors for backend diagnostics. - [x] Add test coverage for exported diagnostic API presence. -- [ ] Adjust the minimal example to capture GLFW error details before cleanup +- [x] Adjust the minimal example to capture GLFW error details before cleanup when a cleanup call could clear the last error. -- [ ] Keep README and architecture docs aligned with the final mcpp-index +- [x] Keep README and architecture docs aligned with the final mcpp-index package names. - If the runtime provider lands as `compat.glvnd`, use that name. - If the package name changes during implementation, update docs only after the index PR settles. -- [ ] Add or update CI build-checks for `examples/minimal_window`. +- [x] Add or update CI build-checks for `examples/minimal_window`. - Runtime execution should stay conditional on a visible display and OpenGL runtime. @@ -46,17 +46,17 @@ it should not package platform OpenGL/GLX/EGL drivers. ## Verification -- [ ] `mcpp build` -- [ ] `mcpp test` -- [ ] `cd examples/basic && mcpp run` -- [ ] `cd examples/minimal_window && mcpp build` -- [ ] `cd examples/glfw_opengl3 && mcpp build` +- [x] `mcpp build` +- [x] `mcpp test` +- [x] `cd examples/basic && mcpp run` +- [x] `cd examples/minimal_window && mcpp build` +- [x] `cd examples/glfw_opengl3 && mcpp build` - [ ] On a machine with working display/runtime closure: `cd examples/minimal_window && mcpp run` ## PR / CI / Merge Notes -- [ ] Commit this plan as the first checkpoint on the feature branch. +- [x] Commit this plan as the first checkpoint on the feature branch. - [ ] Keep current implementation checkpoint commits small. - [ ] Open a PR with sanitized paths and no local machine details. - [ ] Include a test plan that separates build-only CI from display-required diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adeebe3..af60393 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,11 @@ jobs: cd examples/basic mcpp run + - name: Build minimal window example + run: | + cd examples/minimal_window + mcpp build + - name: Build GLFW/OpenGL3 example run: | cd examples/glfw_opengl3 diff --git a/README.md b/README.md index 10e6bdf..46f8e1c 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,22 @@ Dear ImGui 1.92.8 module frame ok ## Backend Example -The GLFW/OpenGL3 example builds on CI but should be run only in an environment -with a working display and OpenGL context: +The minimal GLFW/OpenGL3 window example uses the combined backend module and +does not use `#include` in consumer code: + +```bash +cd examples/minimal_window +mcpp build +mcpp run +``` + +It requires an OpenGL runtime that is visible to the mcpp/xlings runtime. If +GLFW cannot create the window, the example prints the GLFW error text. The +`compat.opengl` package supplies OpenGL registry/header content; it does not +bundle a platform `libGL`/GLX runtime. + +The larger GLFW/OpenGL3 example builds on CI but should be run only in an +environment with a working display and OpenGL context: ```bash cd examples/glfw_opengl3 @@ -94,6 +108,7 @@ The `0.0.1` release state is verified with mcpp `0.0.44`: - `mcpp build` - `mcpp test` - `cd examples/basic && mcpp run` +- `cd examples/minimal_window && mcpp build` - `cd examples/glfw_opengl3 && mcpp build` ## License diff --git a/docs/architecture.md b/docs/architecture.md index 77c4132..93e7f43 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -34,6 +34,7 @@ upstream source ownership in compat packages. | `-- backend_test.cpp `-- examples/ |-- basic/ + |-- minimal_window/ `-- glfw_opengl3/ ``` @@ -81,9 +82,10 @@ Primary proof points: mcpp build mcpp test cd examples/basic && mcpp run +cd ../minimal_window && mcpp build cd ../glfw_opengl3 && mcpp build ``` -The GLFW/OpenGL3 example is a real windowed example. It is build-checked in -headless CI and intended to be run on a machine with a working display/OpenGL -context. +The minimal and full GLFW/OpenGL3 examples are real windowed examples. They are +build-checked in headless CI and intended to be run on a machine with a working +display/OpenGL context. diff --git a/examples/minimal_window/mcpp.toml b/examples/minimal_window/mcpp.toml new file mode 100644 index 0000000..41e80a2 --- /dev/null +++ b/examples/minimal_window/mcpp.toml @@ -0,0 +1,11 @@ +[package] +name = "imgui-minimal-window" +version = "0.1.0" +description = "Minimal GLFW/OpenGL3 window using imgui modules" +license = "MIT" + +[toolchain] +linux = "llvm@20.1.7" + +[dependencies] +imgui = { path = "../.." } diff --git a/examples/minimal_window/src/main.cpp b/examples/minimal_window/src/main.cpp new file mode 100644 index 0000000..24b048e --- /dev/null +++ b/examples/minimal_window/src/main.cpp @@ -0,0 +1,77 @@ +import std; +import imgui.backend.glfw_opengl3; + +namespace { + struct GlfwError { + int code = 0; + const char* description = nullptr; + }; + + GlfwError captureError() { + const char* description = nullptr; + const int errorCode = ImGui::Backend::GlfwOpenGL3::GetError(&description); + return GlfwError{errorCode, description}; + } + + int fail(const char* step, int exitCode, GlfwError error) { + std::println( + "failed at {}: GLFW error {} ({})", + step, + error.code, + error.description != nullptr ? error.description : "no GLFW error description" + ); + return exitCode; + } +} + +int main() { + namespace Backend = ImGui::Backend::GlfwOpenGL3; + + if (!Backend::InitGlfw()) { + return fail("glfwInit", 1, captureError()); + } + + Backend::DefaultWindowHints(); + Backend::ConfigureOpenGL(3, 3, true, false); + + auto* window = Backend::CreateWindow(640, 360, "mcpp imgui minimal window"); + if (window == nullptr) { + const auto error = captureError(); + Backend::TerminateGlfw(); + return fail("glfwCreateWindow", 2, error); + } + + Backend::MakeContextCurrent(window); + Backend::SwapInterval(1); + + ImGuiContext* context = ImGui::CreateContext(); + ImGui::SetCurrentContext(context); + + if (!Backend::Init(window)) { + const auto error = captureError(); + ImGui::DestroyContext(context); + Backend::DestroyWindow(window); + Backend::TerminateGlfw(); + return fail("ImGui GLFW/OpenGL3 backend init", 3, error); + } + + while (!Backend::WindowShouldClose(window)) { + Backend::PollEvents(); + Backend::NewFrame(); + + ImGui::NewFrame(); + ImGui::Begin("Minimal ImGui Window"); + ImGui::TextUnformatted("mcpp module import, no include in consumer code"); + ImGui::End(); + ImGui::Render(); + + Backend::RenderDrawData(ImGui::GetDrawData()); + Backend::SwapBuffers(window); + } + + Backend::Shutdown(); + ImGui::DestroyContext(context); + Backend::DestroyWindow(window); + Backend::TerminateGlfw(); + return 0; +} diff --git a/src/backends/glfw.cppm b/src/backends/glfw.cppm index 8c4bb2b..4c461ce 100644 --- a/src/backends/glfw.cppm +++ b/src/backends/glfw.cppm @@ -24,6 +24,10 @@ export namespace ImGui::Backend::Glfw { return glfwGetVersionString(); } + int GetError(const char** description) { + return glfwGetError(description); + } + void DefaultWindowHints() { glfwDefaultWindowHints(); } diff --git a/src/backends/glfw_opengl3.cppm b/src/backends/glfw_opengl3.cppm index 8726a0d..aacd780 100644 --- a/src/backends/glfw_opengl3.cppm +++ b/src/backends/glfw_opengl3.cppm @@ -20,6 +20,10 @@ export namespace ImGui::Backend::GlfwOpenGL3 { return Glfw::GlfwVersionString(); } + int GetError(const char** description) { + return Glfw::GetError(description); + } + void DefaultWindowHints() { Glfw::DefaultWindowHints(); } diff --git a/tests/backend_test.cpp b/tests/backend_test.cpp index 8a42ee6..c3f4a4c 100644 --- a/tests/backend_test.cpp +++ b/tests/backend_test.cpp @@ -16,6 +16,7 @@ TEST(ImGuiGlfwBackendModuleTest, ExposesPlatformApi) { auto restoreCallbacks = &ImGui::Backend::Glfw::RestoreCallbacks; auto getContentScaleForWindow = &ImGui::Backend::Glfw::GetContentScaleForWindow; auto getContentScaleForMonitor = &ImGui::Backend::Glfw::GetContentScaleForMonitor; + auto getError = &ImGui::Backend::Glfw::GetError; EXPECT_EQ(window, nullptr); EXPECT_EQ(monitor, nullptr); @@ -26,6 +27,7 @@ TEST(ImGuiGlfwBackendModuleTest, ExposesPlatformApi) { EXPECT_NE(restoreCallbacks, nullptr); EXPECT_NE(getContentScaleForWindow, nullptr); EXPECT_NE(getContentScaleForMonitor, nullptr); + EXPECT_NE(getError, nullptr); } TEST(ImGuiOpenGL3BackendModuleTest, ExposesRendererApi) { @@ -52,6 +54,7 @@ TEST(ImGuiGlfwOpenGL3BackendModuleTest, ExposesCombinedApi) { auto shutdown = &ImGui::Backend::GlfwOpenGL3::Shutdown; auto newFrame = &ImGui::Backend::GlfwOpenGL3::NewFrame; auto renderDrawData = &ImGui::Backend::GlfwOpenGL3::RenderDrawData; + auto getError = &ImGui::Backend::GlfwOpenGL3::GetError; EXPECT_NE(initGlfw, nullptr); EXPECT_NE(terminateGlfw, nullptr); @@ -64,4 +67,5 @@ TEST(ImGuiGlfwOpenGL3BackendModuleTest, ExposesCombinedApi) { EXPECT_NE(shutdown, nullptr); EXPECT_NE(newFrame, nullptr); EXPECT_NE(renderDrawData, nullptr); + EXPECT_NE(getError, nullptr); }