GLFWPlatformManager.ixx File
GLFW-backed platform manager handling runtime init, window lifecycle, and frame service commands. More...
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <cassert>
#include <ostream>
#include <ranges>
#include <vector>
#include <helios.engine.platform.window.concepts.IsWindowHandle>
#include <helios.engine.rendering.common.concepts.CanInitializeRenderBackend>
#include <helios.engine.runtime.messaging.command>
#include <
helios.glfw.types>
#include <helios.engine.platform.window.commands>
#include <helios.engine.platform.window.types>
#include <helios.engine.platform.environment.components>
#include <helios.engine.platform.environment.commands>
#include <helios.engine.runtime.world.UpdateContext>
#include <helios.engine.runtime.concepts>
#include <
helios.glfw.components>
#include <helios.engine.core.types>
#include <helios.engine.platform.window.components>
#include <helios.engine.runtime.enginestate.types>
#include <helios.engine.rendering.common.concepts.CanProvideWindowHints>
#include <helios.engine.spatial.components>
#include <helios.engine.rendering.renderTarget>
#include <helios.engine.runtime.messaging.command.concepts.IsPlatformCommandBuffer>
#include <helios.engine.platform.environment.types>
#include <helios.engine.runtime.world.tags.ManagerRole>
#include <helios.engine.runtime.messaging.command.CommandHandlerRegistry>
#include <helios.engine.runtime.world.Session>
#include <helios.engine.util.log>
#include <helios.engine.runtime.messaging.command.CommandBufferRegistry>
#include <helios.engine.state.commands>
#include <helios.engine.platform.lifecycle.commands>
#include <helios.engine.state.types>
#include <helios.engine.runtime.world.EngineWorld>
Namespaces Index
| namespace | helios |
|
|
|
| namespace | glfw |
|
|
|
| namespace | types |
|
|
|
| namespace | components |
|
|
|
| namespace | components |
|
|
|
| namespace | tags |
|
|
|
| namespace | commands |
|
|
|
| namespace | commands |
|
|
|
| namespace | types |
|
|
|
| namespace | components |
|
|
|
| namespace | commands |
|
|
|
| namespace | types |
|
|
|
| namespace | components |
|
|
|
| namespace | commands |
|
|
|
| namespace | types |
|
|
|
| namespace | concepts |
|
|
|
| namespace | types |
|
|
|
| namespace | command |
|
|
|
| namespace | types |
|
|
|
Classes Index
Macro Definitions Index
Description
GLFW-backed platform manager handling runtime init, window lifecycle, and frame service commands.
Macro Definitions
HELIOS_LOG_SCOPE
| #define HELIOS_LOG_SCOPE "helios::glfw::GLFWPlatformManager" |
|
File Listing
The file content with the documentation metadata removed is:
14export module helios.glfw.GLFWPlatformManager;
16import helios.engine.runtime.world.UpdateContext;
17import helios.engine.runtime.world.Session;
19import helios.engine.util.log;
20import helios.engine.core.types;
22import helios.engine.runtime.enginestate.types;
24import helios.engine.spatial.components;
26import helios.engine.rendering.renderTarget;
28import helios.engine.runtime.messaging.command.concepts.IsPlatformCommandBuffer;
29import helios.engine.runtime.messaging.command.CommandHandlerRegistry;
30import helios.engine.runtime.messaging.command.CommandBufferRegistry;
32import helios.engine.state.commands;
33import helios.engine.state.types;
35import helios.engine.runtime.world.EngineWorld;
36import helios.engine.runtime.world.tags.ManagerRole;
38import helios.engine.platform.environment.commands;
39import helios.engine.platform.lifecycle.commands;
40import helios.engine.platform.environment.components;
41import helios.engine.platform.environment.types;
43import helios.engine.platform.window.commands;
44import helios.engine.platform.window.components;
45import helios.engine.platform.window.types;
47import helios.glfw.components;
48import helios.glfw.types;
50import helios.engine.rendering.common.concepts.CanProvideWindowHints;
51import helios.engine.rendering.common.concepts.CanInitializeRenderBackend;
53import helios.engine.runtime.concepts;
54import helios.engine.runtime.messaging.command;
55import helios.engine.platform.window.concepts.IsWindowHandle;
57using namespace helios::engine::rendering::renderTarget::types;
58using namespace helios::engine::rendering::renderTarget::components;
59using namespace helios::engine::spatial::components;
60using namespace helios::engine::runtime::world::tags;
61using namespace helios::engine::platform::environment::commands;
62using namespace helios::engine::platform::lifecycle::commands;
63using namespace helios::engine::platform::environment::types;
64using namespace helios::engine::platform::environment::components;
65using namespace helios::engine::platform::window::commands;
66using namespace helios::engine::platform::window::types;
67using namespace helios::engine::platform::window::components;
70using namespace helios::engine::state::commands;
71using namespace helios::engine::state::types;
72using namespace helios::engine::runtime::messaging::command::concepts;
73using namespace helios::engine::rendering::common::concepts;
74using namespace helios::engine::core::types;
75using namespace helios::engine::runtime::messaging::command;
76using namespace helios::engine::runtime::world;
77using namespace helios::engine::platform::window::concepts;
78using namespace helios::engine::runtime::enginestate::types;
80#define HELIOS_LOG_SCOPE "helios::glfw::GLFWPlatformManager"
93 template<typename TRenderPlatform, typename THandle, typename TStateCommandBuffer = NullCommandBuffer, typename TPlatformCommandBuffer = NullCommandBuffer>
94 requires IsWindowHandle<THandle>
95 && IsCommandBufferLike<TStateCommandBuffer>
96 && IsPlatformCommandBuffer<TPlatformCommandBuffer>
97 && CanInitializeRenderBackend<TRenderPlatform>
98 && CanProvideWindowHints<TRenderPlatform>
101 std::vector<WindowResizeCommand<THandle>> pendingResizeCommands_;
103 std::vector<WindowCreateCommand<THandle>> windowCreateCommands_;
105 std::vector<SwapBuffersCommand<THandle>> pendingBufferSwaps_;
107 std::vector<WindowCloseCommand<THandle>> pendingCloseCommands_;
109 std::vector<THandle> currentContexts_;
111 bool shouldInit_ = false;
113 bool shouldShutdown_ = false;
115 bool pollEvents_ = false;
117 bool initialized_ = false;
119 TRenderPlatform& renderPlatform_;
121 inline static const helios::engine::util::log::Logger& logger_ = helios::engine::util::log::LogManager::loggerForScope(
124 PlatformWorld* platformWorld_;
131 bool initPlatform(UpdateContext& updateContext) noexcept {
133 if (!shouldInit_ || initialized_) {
137 if (glfwInit() == GLFW_FALSE) {
138 assert(false && "Failed to initialize glfw");
141 renderPlatform_.provideWindowHints();
143 assert(updateContext.session().state<EngineState>() == EngineState::Booting &&
144 "Expected EngineState to be Booting during platform initialization");
146 initialized_ = updateContext.session().initialize() &&
147 updateContext.runtimeEnvironment().initialize();
163 bool createWindow(UpdateContext& updateContext, const WindowCreateCommand<THandle>& cmd) noexcept {
165 auto window = updateContext.find(cmd.windowHandle);
171 auto& cfg = cmd.windowConfig;
173 auto* nativeHandle = glfwCreateWindow(
181 assert(nativeHandle && "Failed to create GLFW window");
183 if (cfg.aspectRatioNumer > 0 && cfg.aspectRatioDenom > 0) {
184 glfwSetWindowAspectRatio(
186 cfg.aspectRatioNumer,
191 assert(window->template has<WindowCreateRequestComponent<THandle>>() && "Expected entity to have WindowCreateRequestComponent");
192 window->template remove<WindowCreateRequestComponent<THandle>>();
193 assert(!window->template has<WindowCreateRequestComponent<THandle>>() && "Expected entity to not have WindowCreateRequestComponent");
194 assert(!window->template has<WindowComponent<THandle>>() && "Expected entity to not have WindowComponent");
195 window->template add<WindowComponent<THandle>>(
196 std::move(cfg.title),
197 cfg.aspectRatioNumer,
200 window->template add<
201 Size2DComponent<THandle>
202 >(WindowSize(cfg.size));
203 window->template add<GLFWWindowHandleComponent<THandle>>(nativeHandle);
205 removeCurrentContext(updateContext);
207 glfwMakeContextCurrent(nativeHandle);
209 window->template add<CurrentContextComponent<THandle>>();
211 window->template add<WindowShownComponent<THandle>>();
212 window->template add<GLFWWindowUserPointerComponent<THandle, TPlatformCommandBuffer>>(
214 cmd.windowHandle, commandBufferRegistry_->template item<TPlatformCommandBuffer>()
217 installResizeListener(cmd.windowHandle);
220 int renderTargetWidth = 0;
221 int renderTargetHeight = 0;
223 int windowHeight = 0;
225 glfwGetFramebufferSize(nativeHandle, &renderTargetWidth, &renderTargetHeight);
226 glfwGetWindowSize(nativeHandle, &windowWidth, &windowHeight);
228 commandBufferRegistry_->template item<TPlatformCommandBuffer>()
229 ->template add<WindowResizeCommand<THandle>>(
231 WindowSize(windowWidth, windowHeight),
232 RenderTargetSize(renderTargetWidth, renderTargetHeight));
242 void removeCurrentContext(UpdateContext& updateContext) {
244 currentContexts_.clear();
245 for (auto [window, cc]: updateContext.template view<THandle, CurrentContextComponent<THandle>>()) {
246 currentContexts_.push_back(window.handle());
248 for (auto& handle : currentContexts_) {
249 auto go = updateContext.find<THandle> (handle);
251 go->template remove<CurrentContextComponent<THandle>>();
261 void installResizeListener(THandle handle) noexcept {
263 auto entity = platformWorld_->findEntity<THandle>(handle);
266 logger_.warn("Entity was not found");
270 const auto* glfw = entity->template get<GLFWWindowHandleComponent<THandle>>();
272 logger_.error("Entity does not have GLFWWindowHandleComponent");
273 assert(false && "Entity does not have GLFWWindowHandleComponent");
277 auto* wuptrComponent = entity->template get<GLFWWindowUserPointerComponent<THandle, TPlatformCommandBuffer>>();
278 if (!wuptrComponent) {
279 logger_.error("Entity does not have GLFWWindowUserPointerComponent");
280 assert(false && "Entity does not have GLFWWindowUserPointerComponent");
283 auto* wuptr = &wuptrComponent->userPointer;
285 glfwSetWindowUserPointer(glfw->handle, static_cast<void*>(wuptr));
287 glfwSetFramebufferSizeCallback(
289 [] (GLFWwindow* nativeHandle, const int width, const int height) {
290 const auto* ptr = static_cast<GLFWWindowUserPointer<THandle, TPlatformCommandBuffer>*>(glfwGetWindowUserPointer(nativeHandle));
292 if (ptr && ptr->platformCommandBuffer) {
295 int windowHeight = 0;
297 glfwGetWindowSize(nativeHandle, &windowWidth, &windowHeight);
298 ptr->platformCommandBuffer->template add<WindowResizeCommand<THandle>>(
300 WindowSize(windowWidth, windowHeight),
301 RenderTargetSize(width, height)
314 void swapBuffer(UpdateContext& updateContext, const SwapBuffersCommand<THandle>& cmd) noexcept {
316 const auto entity = updateContext.find(cmd.windowHandle);
319 logger_.warn("Entity was not found");
323 const auto* glfw = entity->template get<GLFWWindowHandleComponent<THandle>>();
326 logger_.error("Entity does not have GLFWWindowHandleComponent");
327 assert(false && "Entity does not have GLFWWindowHandleComponent");
331 assert((updateContext.session().state<EngineState>() != EngineState::Booting) &&
332 "GLFWSwapBuffersSystem should not be running during boot");
333 assert(glfw->handle && "GLFWWindowComponent has no native handle");
334 glfwSwapBuffers(glfw->handle);
345 bool createWindows(UpdateContext& updateContext) noexcept {
346 if (windowCreateCommands_.empty()) {
349 for (const auto& windowCreateCommand : windowCreateCommands_) {
350 const bool isContextAvailable = createWindow(updateContext, windowCreateCommand);
351 if (!isContextAvailable) {
352 logger_.error("Failed to create window");
353 assert(false && "Failed to create window");
357 windowCreateCommands_.clear();
370 void resizeWindows(UpdateContext& updateContext) noexcept {
372 if (pendingResizeCommands_.empty()) {
376 for (const auto& [windowHandle, windowSize, renderTargetSize]: pendingResizeCommands_) {
378 if (!windowHandle.isValid()) {
382 if (auto entity = updateContext.find(windowHandle)) {
384 if (auto* wsc = entity->template get<Size2DComponent<THandle>>()) {
385 wsc->setValue(windowSize);
387 if (auto* fbc = entity->template get<RenderTargetBindingComponent<THandle>>()) {
388 auto renderTargetHandle = fbc->targetHandle();
389 auto renderTarget = updateContext.find<RenderTargetHandle>(renderTargetHandle);
390 auto fsc = renderTarget->template get<Size2DComponent<RenderTargetHandle>>();
392 logger_.info("Setting renderTarget size to {0},{1}", renderTargetSize[0], renderTargetSize[1]);
393 fsc->setValue(renderTargetSize);
399 pendingResizeCommands_.clear();
407 void swapBuffers(UpdateContext& updateContext) noexcept {
408 if (pendingBufferSwaps_.empty()) {
411 for (const auto& swapBufferCommand : pendingBufferSwaps_) {
412 swapBuffer(updateContext, swapBufferCommand);
414 pendingBufferSwaps_.clear();
422 void pollEvents(UpdateContext& updateContext) noexcept {
436 void closeWindows(UpdateContext& updateContext) noexcept {
437 if (pendingCloseCommands_.empty()) {
441 for (const auto& cmd : pendingCloseCommands_) {
442 auto entity = updateContext.find(cmd.windowHandle);
445 logger_.warn("Entity was not found");
449 const auto* glfw = entity->template get<GLFWWindowHandleComponent<THandle>>();
451 logger_.warn("Entity does not have GLFWWindowHandleComponent");
455 glfwDestroyWindow(glfw->handle);
456 bool destroyed = platformWorld_->destroy<THandle>(cmd.windowHandle);
457 assert(destroyed && "Failed to destroy entity");
460 pendingCloseCommands_.clear();
469 void shutdown(UpdateContext& updateContext) noexcept {
473 commandBufferRegistry_->template item<TStateCommandBuffer>()->template add<StateCommand<EngineState>>(
474 StateTransitionRequest<EngineState>(
475 updateContext.session().state<EngineState>(),
476 EngineStateTransitionId::ShutdownRequest
483 CommandBufferRegistry* commandBufferRegistry_ = nullptr;
494 TRenderPlatform& renderPlatform,
495 PlatformWorld& platformWorld,
496 CommandBufferRegistry& commandBufferRegistry)
497 : renderPlatform_(renderPlatform),
498 platformWorld_(&platformWorld),
499 commandBufferRegistry_(&commandBufferRegistry) {};
507 void flush(UpdateContext& updateContext) noexcept {
509 if (shouldShutdown_) {
510 shutdown(updateContext);
514 if (initPlatform(updateContext)) {
515 commandBufferRegistry_->template item<TStateCommandBuffer>()->template add<StateCommand<EngineState>>(
516 StateTransitionRequest<EngineState>(
517 updateContext.session().state<EngineState>(),
518 EngineStateTransitionId::BootRequest
522 pollEvents(updateContext);
523 const bool isContextAvailable = createWindows(updateContext);
525 if (!renderPlatform_.isInitialized() && isContextAvailable) {
526 if (renderPlatform_.init()) {
527 updateContext.runtimeEnvironment().setGPUReady();
531 resizeWindows(updateContext);
532 closeWindows(updateContext);
533 swapBuffers(updateContext);
543 bool submit(const PollEventsCommand& command) noexcept {
555 bool submit(const PlatformInitCommand& command) noexcept {
556 assert(!initialized_ && "Application was already initialized.");
568 bool submit(const WindowCreateCommand<THandle>& command) noexcept {
569 windowCreateCommands_.push_back(command);
580 bool submit(const SwapBuffersCommand<THandle>& command) noexcept {
581 pendingBufferSwaps_.push_back(command);
592 bool submit(const WindowResizeCommand<THandle>& command) noexcept {
593 const auto idx = command.windowHandle.entityId;
595 if (pendingResizeCommands_.size() <= idx) {
596 pendingResizeCommands_.resize(idx + 1);
599 pendingResizeCommands_[idx] = command;
610 bool submit(const WindowCloseCommand<THandle>& command) noexcept {
611 pendingCloseCommands_.push_back(command);
622 bool submit(const ShutdownCommand& command) noexcept {
623 shouldShutdown_ = true;
632 void init(CommandHandlerRegistry& commandHandlerRegistry) noexcept {
634 commandHandlerRegistry.handleCommands<
635 WindowCreateCommand<THandle>,
637 WindowResizeCommand<THandle>,
638 SwapBuffersCommand<THandle>,
640 WindowCloseCommand<THandle>,
Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.