Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .agents/docs/2026-06-03-gl-runtime-boundary-plan.md
Original file line number Diff line number Diff line change
@@ -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.
- [x] Adjust the minimal example to capture GLFW error details before cleanup
when a cleanup call could clear the last error.
- [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.
- [x] 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

- [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

- [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
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.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ upstream source ownership in compat packages.
| `-- backend_test.cpp
`-- examples/
|-- basic/
|-- minimal_window/
`-- glfw_opengl3/
```

Expand Down Expand Up @@ -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.
11 changes: 11 additions & 0 deletions examples/minimal_window/mcpp.toml
Original file line number Diff line number Diff line change
@@ -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 = "../.." }
77 changes: 77 additions & 0 deletions examples/minimal_window/src/main.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
4 changes: 4 additions & 0 deletions src/backends/glfw.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export namespace ImGui::Backend::Glfw {
return glfwGetVersionString();
}

int GetError(const char** description) {
return glfwGetError(description);
}

void DefaultWindowHints() {
glfwDefaultWindowHints();
}
Expand Down
4 changes: 4 additions & 0 deletions src/backends/glfw_opengl3.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
4 changes: 4 additions & 0 deletions tests/backend_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -64,4 +67,5 @@ TEST(ImGuiGlfwOpenGL3BackendModuleTest, ExposesCombinedApi) {
EXPECT_NE(shutdown, nullptr);
EXPECT_NE(newFrame, nullptr);
EXPECT_NE(renderDrawData, nullptr);
EXPECT_NE(getError, nullptr);
}
Loading