diff --git a/src/steam/engine/engine-ctx.cpp b/src/steam/engine/engine-ctx.cpp index a363e3f11..ff5f0a31b 100644 --- a/src/steam/engine/engine-ctx.cpp +++ b/src/steam/engine/engine-ctx.cpp @@ -13,65 +13,46 @@ /** @file engine-ctx.cpp - ** Base implementation of render engine operational service configuration. + ** Base implementation of render engine operational service access. + ** This singleton implementation provides and configures the access point, + ** while the actual [»facilities«](engine-facilities.hpp), which are retrieved + ** through interface methods, can be configured with the help of the + ** [Dependency-Injection framework](depend-inject.hpp) ** @warning as of 1/2026 a preliminary integration of Render-Engine underway ////////////////////////////////////////TICKET #1367 */ #include "steam/engine/engine-ctx.hpp" -#include "steam/engine/engine-ctx-facilities.hpp" -#include "steam/engine/tracking-heap-block-provider.hpp" - -//#include -//#include -//#include +#include "steam/engine/engine-facilities.hpp" - -namespace steam { +namespace steam { namespace engine{ -// using std::string; -// using lumiera::Subsys; -// using std::function; -// using std::bind; - using std::make_unique; -// using std::ref; - - - namespace { // hidden local details of the service implementation.... - - } // (End) hidden service impl details - - - /** storage for the EngineService interface object */ lib::Depend EngineCtx::access; - - - EngineCtx::~EngineCtx() { } - - /** */ - EngineCtx::EngineCtx() - : services_{make_unique()} - , mem {services_->getMemProvider()} - , cache{services_->getCacheProvider()} - { } - - - /** */ - EngineCtx::Facilities::Facilities() - : memProvider_{make_unique()} ////////////////////////////////////////TICKET #1367 : only suitable for first prototype - , cacheProvider_{} - { } + /** configurable access point to the »Engine Facilities« */ + lib::Depend accessEngineFacilities; - /** core operation: blah blubb.... + /** + * Bootstrap the EngineCtx access front-end. + * The EngineCtx object instance is created on-demand through + * lib::Depend; at that point, a service implementation + * of the EngineFacilities is accessed; when used from a test setup, + * this will be a "naive" implementation, based on heap allocations. + * For the actual Render Engine, the EngineEnvironment must been + * bootstrapped prior to this first access, to make the full set + * of Render Engine services available through this interface. */ + EngineCtx::EngineCtx() + : mem {accessEngineFacilities().setupBufferProvider()} + , cache{accessEngineFacilities().setupCacheProvider()} + { } diff --git a/src/steam/engine/engine-ctx.hpp b/src/steam/engine/engine-ctx.hpp index 6eda11d03..87e3a983b 100644 --- a/src/steam/engine/engine-ctx.hpp +++ b/src/steam/engine/engine-ctx.hpp @@ -16,9 +16,12 @@ ** Notably the services to provide access to working buffers are linked directly into the ** render node connectivity, where they are used for each invocation of a render job. ** - ** The EngineCtx itself is meant to be [dependency injected](\ref lib::Depend), so that - ** tests can use suitably adapted variants for verifications. The default instantiation - ** provides a naive self-contained implementation suitable for demonstration and test. + ** The EngineCtx itself is meant to be [dependency injected](\ref lib::Depend), and acts + ** as a front-end for the support facilities of the render engine — which are likewise + ** dependency-injected, so that tests can use suitably adapted variants for verification. + ** The default instantiation provides a naive self-contained implementation suitable for + ** demonstration and test. + ** ** For productive use within the Lumiera Render Engine, a much more elaborate setup ** is necessary, including setup of a frame cache, and of timing strategies; these ** are configured as part of starting the steam::engine::RenderEnvironment. @@ -42,8 +45,6 @@ #include "steam/engine/buffhandle.hpp" #include "lib/nocopy.hpp" -#include - namespace steam { namespace engine { @@ -52,23 +53,18 @@ namespace engine { class EngineCtx : util::NonCopyable { - class Facilities; - std::unique_ptr services_; public: BufferProvider& mem; - BufferProvider& cache; + BufferProvider& cache; /////////////////////////////////////////////////////////////////////////////TICKET #1223 : very likely a super interface for the CacheService static lib::Depend access; private: - ~EngineCtx(); EngineCtx(); - friend class lib::DependencyFactory; }; - }} // namespace steam::engine #endif /*STEAM_ENGINE_ENGINE_CTX_H*/ diff --git a/src/steam/engine/engine-facilities.hpp b/src/steam/engine/engine-facilities.hpp index 61a99d8f3..95255e9af 100644 --- a/src/steam/engine/engine-facilities.hpp +++ b/src/steam/engine/engine-facilities.hpp @@ -12,17 +12,19 @@ */ /** @file engine-facilities.hpp - ** Implementation of render engine operational configuration and services. + ** Interface to setup and access the render engine configuration and services. ** Without further setup, [dependency injection](\ref depend.hpp) will establish a ** minimalistic default instantiation of these services, sufficient for demonstration ** and tests. For the real render engine however, dedicated service instances will be - ** created and managed actively. + ** created and managed actively, by the [»Render Environment«](\ref RenderEnvironment). ** @todo and we'll have yet to »figure out« what specifically to do for these ** services and how to start an active render engine for productive use. - ** @deprecated 1/2026 I'm unhappy with this convoluted structure; - ** my intention is to fuse that with the engine-ctx.cpp implementation. + ** @remark this seemingly convoluted setup with several layers of abstraction is + ** necessary to allow for "simple use without much ado" in a test scenario, + ** while having a fully controlled lifecycle for the actual Render Engine. ** ** @see engine-ctx.hpp + ** @see engine-service.hpp ** @see weaving-pattern-builder.hpp */ @@ -31,45 +33,23 @@ #include "steam/engine/engine-ctx.hpp" -#include "steam/engine/buffer-provider.hpp" #include "lib/nocopy.hpp" -//#include -#include - namespace steam { -namespace engine { +namespace engine{ -// using lib::Literal; - using std::unique_ptr; -// using std::forward; - - class EngineCtx::Facilities + class EngineFacilities : util::NonCopyable { - unique_ptr memProvider_; - unique_ptr cacheProvider_; public: - Facilities(); + virtual ~EngineFacilities() { } ///< this is an interface - BufferProvider& - getMemProvider() - { - REQUIRE (memProvider_); - return *memProvider_; - } - - BufferProvider& - getCacheProvider() - { - return cacheProvider_? *cacheProvider_ - : *memProvider_; - } + virtual BufferProvider& setupBufferProvider(); + virtual BufferProvider& setupCacheProvider(); ///////////////////////////////////////////////////////TICKET #1223 : very likely super interface required for the CacheService }; - }} // namespace steam::engine #endif /*STEAM_ENGINE_ENGINE_CTX_FACILITIES_H*/ diff --git a/src/steam/engine/engine-service.cpp b/src/steam/engine/engine-service.cpp index a438cf6ea..79755a718 100644 --- a/src/steam/engine/engine-service.cpp +++ b/src/steam/engine/engine-service.cpp @@ -19,6 +19,7 @@ #include "steam/engine/engine-service.hpp" +#include "steam/engine/render-environment.hpp" #include "lib/itertools.hpp" //#include diff --git a/src/steam/engine/render-drive.hpp b/src/steam/engine/render-drive.hpp index 21934a30f..ceed456b9 100644 --- a/src/steam/engine/render-drive.hpp +++ b/src/steam/engine/render-drive.hpp @@ -31,8 +31,8 @@ #define STEAM_ENGINE_RENDER_DRIVE_H #include "steam/common.hpp" +#include "steam/engine/render-environment.hpp" #include "steam/mobject/model-port.hpp" -#include "steam/engine/dispatcher.hpp" #include "steam/play/timings.hpp" #include "vault/gear/job.h" //#include "lib/nocopy.hpp" @@ -52,23 +52,6 @@ namespace engine { using lib::HashVal; - /** - * Abstract definition of the environment - * hosting a given render activity (CalcStream). - * Exposes all the operations necessary to adjust the - * runtime behaviour of the render activity, like e.g. - * re-scheduling with modified playback speed. Since the - * CalcStream is an conceptual representation of "the rendering", - * the actual engine implementation is kept opaque this way. - */ - class RenderEnvironment - { - public: - virtual ~RenderEnvironment() { } ///< this is an interface - - virtual play::Timings& effectiveTimings() =0; - virtual Dispatcher& getDispatcher() =0; - }; /** diff --git a/src/steam/engine/render-environment.cpp b/src/steam/engine/render-environment.cpp new file mode 100644 index 000000000..0984bdde6 --- /dev/null +++ b/src/steam/engine/render-environment.cpp @@ -0,0 +1,73 @@ +/* + RenderEnvironment - setup of the Lumiera Render Engine + + Copyright (C) + 2026, Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +* *****************************************************************/ + + +/** @file render-environment.cpp + ** Base implementation of render engine operational service access. + ** This singleton implementation provides and configures the access point, + ** while the actual [»facilities«](engine-facilities.hpp), which are retrieved + ** through interface methods, can be configured with the help of the + ** [Dependency-Injection framework](depend-inject.hpp) + ** @warning as of 1/2026 a preliminary integration of Render-Engine underway ////////////////////////////////////////TICKET #1367 + */ + + +#include "steam/engine/render-environment.hpp" +#include "steam/engine/engine-facilities.hpp" +#include "steam/engine/buffer-provider.hpp" +#include "steam/engine/tracking-heap-block-provider.hpp" + + +namespace steam { +namespace engine{ + + + namespace { + /** A simplistic buffer manager for tests + * (Meyer's Singleton) */ + BufferProvider& + getNaiveBufferManager() + { + static TrackingHeapBlockProvider buffProvider; //////////////////////////////////////////////////TICKET #1367 : only suitable for first prototype; should implement a bare bone memory manager instead + return buffProvider; + } + } + + /* ===== Render Environment Implementation ===== */ + + + /////////////////////////////////////////////////////////////TODO + /// The real Render Engine needs a well defined life cycle; + /// services must be booted and shut down. + /// Notably a dedicated serivce-like subclass of EngineCtx + /// must be created here and installed for lib::Depend + /// + + + /* ===== Access to Render Engine Facilities ===== */ + + BufferProvider& + EngineFacilities::setupBufferProvider() + { + return getNaiveBufferManager(); + } + + BufferProvider& + EngineFacilities::setupCacheProvider() ////////////////////////////////////////////////////////////////TICKET #1223 : in what ways does client code need to interact with the Frame Cache / Management? + { + return getNaiveBufferManager(); + } + + + +}} // namespace steam::engine diff --git a/src/steam/engine/render-environment.hpp b/src/steam/engine/render-environment.hpp new file mode 100644 index 000000000..47227b7af --- /dev/null +++ b/src/steam/engine/render-environment.hpp @@ -0,0 +1,66 @@ +/* + RENDER-ENVIRONMENT.hpp - setup of the Lumiera Render Engine + + Copyright (C) + 2026, Hermann Vosseler + +  **Lumiera** is free software; you can redistribute it and/or modify it +  under the terms of the GNU General Public License as published by the +  Free Software Foundation; either version 2 of the License, or (at your +  option) any later version. See the file COPYING for further details. + +*/ + + +/** @file render-environment.hpp + ** The active core within a CalcStream, causing the render mechanism to re-trigger repeatedly. + ** Rendering is seen as an open-ended, ongoing process, and thus the management and planning + ** of the render process itself is performed chunk wise and embedded into the other rendering + ** calculations. The _"rendering-as-it-is-planned-right-now"_ can be represented as a closure + ** to the jobs, which perform and update this plan on the go. And in fact, the head of the + ** planning process, the CalcStream, maintains this closure instance, as parametrised + ** with the appropriate configuration for the specific playback/render process underway. + ** Enclosed into this instance lives the actual job planning pipeline, connected at the + ** rear to the dispatcher and thus to the fixture and the low-level model + ** + ** @todo 4/2023 »Playback Vertical Slice« -- effort towards first integration of render process ////////////TICKET #1221 + */ + + +#ifndef STEAM_ENGINE_RENDER_ENVIRONMENT_H +#define STEAM_ENGINE_RENDER_ENVIRONMENT_H + +#include "steam/common.hpp" +#include "steam/engine/dispatcher.hpp" +#include "steam/play/timings.hpp" +//#include "lib/nocopy.hpp" + + +namespace steam { +namespace engine { + + + + /** + * Abstract definition of the environment + * hosting a given render activity (CalcStream). + * Exposes all the operations necessary to adjust the + * runtime behaviour of the render activity, like e.g. + * re-scheduling with modified playback speed. Since the + * CalcStream is an conceptual representation of "the rendering", + * the actual engine implementation is kept opaque this way. + */ + class RenderEnvironment + { + public: + virtual ~RenderEnvironment() { } ///< this is an interface + + virtual play::Timings& effectiveTimings() =0; + virtual Dispatcher& getDispatcher() =0; + }; + + + + +}} // namespace steam::engine +#endif /*STEAM_ENGINE_RENDER_ENVIRONMENT_H*/ diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 50d6bcbe9..d409fc9d1 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -77418,6 +77418,15 @@ + + + + + + + + + @@ -99842,13 +99851,17 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +
- + @@ -99857,6 +99870,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+
@@ -110507,7 +110521,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + @@ -110531,7 +110547,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + @@ -110732,7 +110750,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -110853,7 +110871,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -110861,15 +110880,347 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + + + + + + + + +

+ ...denn dieser Code-Pfad ist zu betrachten im Verhältnis zu einer Media-Processing-Funciton, die Millionen von Iterationen macht +

+ +
+
+ + + + +

+ ...weil ich eine echte, dynamische Wahlmöglichkeit schaffen möchte (wenngleich auch im realen Betrieb immer eine einzige feste Implementierungsklasse zum Einsatz kommen dürfte) — deshalb kann der Compiler keine Monomorphic-Optimisation machen, sondern muß die Referenz als Pointer implementieren +

+ +
+
+ + + + + +

+ für die Performance ist nichts gewonnen — aber auch nichts verloren +

+ +
+
+
+ + + + +

+ das könnte man auch in einer Subklasse tun; mir erschien aber die Schreibweise klarer: EngineCtx::access().mem.lockBufferFor<Type>() anstatt einem getBufferProvider() — das heißt, ich möchte die Abstraktion »Buffer Provider« oder »Cache Provider« nicht eigens hervorheben; außerdem kann so die ganze Implementierung in einem File beieinander stehen, und man spart sich ein weiteres leeres, nichtsagendes  Interface, welches nur aus Gettern besteht. Ja, Getter halte ich inzwischen für ein Antipattern +

+ + +
+
+ + + + + + +

+ ...weil zum Zeitpunkt des Basis-Konstruktor-Aufrufs die VTable der abgeleiteten Klasse noch gar nicht definiert ist +

+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ so wie gebaut geht es grade eben, +

+

+ aber ist nicht wirklich konfigurierbar, +

+

+ und sehr verwirrend... +

+ +
+ +
+
+ + + + + + + + + + +

+ Ja könnte... +

+

+ ABER dann könnte man nicht mehr ohne weitere Vorbereitung den Accessor lib::Depend<EngineCtx> verwenden. Er würde dann nämlich einen Fehler werfen (weil man die ABC gar nicht instantiieren kann). Grundsätzlich so machbar; dann müßte aber jeder Test irgend etwas explizit tun, oder man müßte irgendwo auf Ebene der Library-Linkage spezielle magische Tricks anwenden... +

+ +
+ +
+ + + + +

+ »Principle of least Surprise«: +

+
    +
  • + lib::Debpend<EngineCtx> kann man without much ado einfach verwenden. +
  • +
  • + die Default-Implementierung sollte nicht speziell instrumentiert sein, sondern grade gut genug für Demo- und Test-Code +
  • +
  • + für Tests mit Verifikation sollte man eine konfigurierbare Subklasse einsetzen, und dort in Instrumentierung injizieren +
  • +
  • + für den Produktiv-Betrieb kann eine ander Subklasse verwendet werden, die man an geeigneter Stelle mit viel Trara erzeugt und in die Dependency-Factory installiert +
  • +
+ +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + +

+ der Zugriff per lib::Depend<Facilities> ist der eigentliche Konfigurationspunkt +

+ +
+ +
+
+ + + + + + + +

+ ...mit dieser kann man einen konkreten Sub-Typ instantiieren; das sollte für alle Test-Belange ausreichen +

+ +
+ +
+ + + + +

+ das Nutzungs-Interface bleibt komplett unverändert +

+ +
+
+ + + + +
- + + + + + + + + + + +

+ »damals« hatten „wir“ nur Vorstellungen +

+ +
+
+ + + + + +

+ ...nämlich im Builder, welcher per Architektur-Beschluß als einfache Operation ablaufen soll, soweit überhaupt möglich in einem einzigen Thread. +

+ +
+
+ + + + +
    +
  • + hochgradig concurrent +
  • +
  • + nicht-deterministische Zeitfolge +
  • +
  • + jede Latenz ist potentiell gefährlich, vor allem Cache-Misses +
  • +
+ +
+
+ + + + +

+ Das ist inspiriert von einer ähnlichen Idee in Christian's Mem-Mapping-Backend: Für die latenz gefährliche Vorbereitungen schickt man mit einem gewissen Vorlauf bereits auf den Weg, so daß höchstwahrscheinlich nur noch ein Fence notwenig ist, um das vorbereitete Ergebnis aufzugreifen. In meinem Fall könnte inzwischen eine asynchrone Resourcen-Anfrage bearbeitet werden. +

+ +
+
+
+ + + + + +

+ Es gibt da einen »Key« und einen »Entry«, welcher ein erweiterter Key ist, und auf magische Weise am Hash hängt; meiner Einschätzung nach Bauchgefühl zufolge liegt hier das Problem, und nicht sosehr darin, daß zusätzliche Metadaten im Hash erfaßt werden müssen +

+ +
+
+ + + + +

+ Das API bzw. das dazugehörige Protokoll diktiert lediglich eine gewisse Sequenzierung:  ab einem gewissen Punkt geht es um einen konkreten Buffer diesen Typs, über dessen weitere Relevanz nichts bekannt ist +

+ +
+
+ + + +
+ + + + + + +

+ ich sehe das aber als Gelegenheit, das alte Design »aus den Angeln zu heben« +

+ +
+
+ + + + + + + + +

+ aber in der realen Engine gibt es »unvollständige Information« +

+ +
+ + + +

+ nämlich wenn jemand in irgend einem Thread jetzt sofort einen Buffer braucht, oder zu rasch nach dem Anouncement den konkreten Buffer belegen möchte: dann müssen wir nämlich lokal handeln — und es könnte sein, daß uns dazu wichtige Informationen fehlen (wiewohl sich das rein aus Interna der Implementierung ergibt und am Ende irrelevant sein könnte) +

+ +
+
+
+
+
@@ -163177,7 +163528,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
- + @@ -168016,7 +168367,7 @@ that situation will improve in forseeable future. - + @@ -168310,7 +168661,7 @@ that situation will improve in forseeable future. - + @@ -168509,6 +168860,10 @@ that situation will improve in forseeable future. + + + + @@ -176058,6 +176413,8 @@ runner.run(test_suite())

+ + @@ -176253,6 +176610,8 @@ runner.run(test_suite())
+ + @@ -198496,6 +198855,26 @@ env.Command('out.bin', 'in.bin', my_action) + + + + + + + + + + + + +

+ im Trac-Git-Repo: 1dd6a9cc60684504a95b3ec0280714f27756dbff  (22.12.2025) +

+ +
+
+
+