From a1e22c26ababac87c2f8eba39e309c500b68b0bb Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 5 Sep 2026 14:05:12 -0400 Subject: [PATCH] [Build] (MG_Remote, Protocol): pin the flatbuffers submodule, add the control-plane schema and commit its generated header - 3rdparty/flatbuffers submodule pinned to the latest release tag v25.12.19 (7e163021). The runtime is header-only, so only 3rdparty/flatbuffers/include is ever used and no library is linked; CMake never calls add_subdirectory on it and flatc is not in the build graph (plan B section 8.1, inheriting the earlier plan's section 7.1). - MobileGL/MG_Remote/Protocol/protocol.fbs carries the CONTROL PLANE only: SegmentRef, Hello, Welcome, CapsSnapshot, DefaultFramebufferInfo, SurfaceOp, SurfaceReply, ResyncRequest, ResyncDone, AuxRequest, Fatal, LogLine, union CtrlMsg and the CtrlEnvelope root with a file_identifier. Hot-path records are FlatBuffers structs generated from MG_Pipe/PipeCalls.def in a later package and are deliberately absent here, so record numbering never churns. - Two deviations from the earlier plan's section 7.1 sketch, both deliberate: (a) ProgramReflection is not a union member - plan B ships program artifacts inside the create_shader_state CSO blob (section 8.2), and union tags are wire values that may only ever be appended, so reserving a tag for a message that may never exist is worse than appending one later; (b) maxComputeWorkGroupCount/Size are vectors, not [int:3] - fixed-size arrays are legal only in FlatBuffers structs, never in tables. - scripts/gen_protocol.py resolves flatc as MOBILEGL_FLATC_EXECUTABLE, otherwise builds the pinned flatc ONCE into /../flatc-build (override with MOBILEGL_FLATC_BUILD_DIR), outside the project build graph. A flatc found on PATH is deliberately refused and a version mismatch against the pinned runtime is a hard error: the generated header static_asserts FLATBUFFERS_VERSION, so a stray flatc either fails to compile or churns the committed file on every machine. The earlier branch did the opposite - Protocol/CMakeLists.txt:22-38 add_subdirectory'd the FlatBuffers tree with FLATBUFFERS_BUILD_FLATC=ON whenever MOBILEGL_FLATC_EXECUTABLE was unset, which is exactly the NDK trap it claimed to avoid (cross-compile an arm64 flatc, then run it on the host). - protocol_generated.h is committed with the project source header prepended by the generator, so regeneration is byte-identical: verified by running gen_protocol.py twice and by perturbing the file and regenerating it back. - Reuse from Feat/CS-Delta-IPC: MobileGL/Protocol/mg_protocol_base.h, kept as the shared C vocabulary (result codes, byte spans, shm region, id typedefs) and keeping the structSize-first versioning discipline that section 14.2 calls the answer to risk B-R10. Dropped from it: MobileGLObjectKind / MobileGLObjectScope / MobileGLObjectHandle - plan B never puts GL object identity on the wire (the frontend allocates {slot, generation} handles in MG_Pipe, section 4.2.1), so a second identity vocabulary would be a drift surface with no reader. Added MOBILEGL_ERR_BUFFER_TOO_SMALL as an append-only code for the receive contract. --- .gitmodules | 3 + 3rdparty/flatbuffers | 1 + .../Protocol/generated/protocol_generated.h | 1778 +++++++++++++++++ .../MG_Remote/Protocol/mg_protocol_base.h | 120 ++ MobileGL/MG_Remote/Protocol/protocol.fbs | 235 +++ scripts/gen_protocol.py | 175 ++ 6 files changed, 2312 insertions(+) create mode 160000 3rdparty/flatbuffers create mode 100644 MobileGL/MG_Remote/Protocol/generated/protocol_generated.h create mode 100644 MobileGL/MG_Remote/Protocol/mg_protocol_base.h create mode 100644 MobileGL/MG_Remote/Protocol/protocol.fbs create mode 100644 scripts/gen_protocol.py diff --git a/.gitmodules b/.gitmodules index 3ae968ea..20ea8361 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "include/ska"] path = include/ska url = https://github.com/MobileGL-Dev/flat_hash_map.git +[submodule "3rdparty/flatbuffers"] + path = 3rdparty/flatbuffers + url = https://github.com/google/flatbuffers.git diff --git a/3rdparty/flatbuffers b/3rdparty/flatbuffers new file mode 160000 index 00000000..7e163021 --- /dev/null +++ b/3rdparty/flatbuffers @@ -0,0 +1 @@ +Subproject commit 7e163021e59cca4f8e1e35a7c828b5c6b7915953 diff --git a/MobileGL/MG_Remote/Protocol/generated/protocol_generated.h b/MobileGL/MG_Remote/Protocol/generated/protocol_generated.h new file mode 100644 index 00000000..eb91a6a5 --- /dev/null +++ b/MobileGL/MG_Remote/Protocol/generated/protocol_generated.h @@ -0,0 +1,1778 @@ +// MobileGL - MobileGL/MG_Remote/Protocol/generated/protocol_generated.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +// GENERATED FILE - DO NOT EDIT. +// Regenerate with `python3 scripts/gen_protocol.py` after changing +// MobileGL/MG_Remote/Protocol/protocol.fbs. CI's flatc-check step regenerates +// this file and fails on `git diff --exit-code`. + +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_PROTOCOL_MOBILEGL_WIRE_H_ +#define FLATBUFFERS_GENERATED_PROTOCOL_MOBILEGL_WIRE_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); + +namespace MobileGL { +namespace Wire { + +struct SegmentRef; +struct SegmentRefBuilder; + +struct Hello; +struct HelloBuilder; + +struct Welcome; +struct WelcomeBuilder; + +struct CapsSnapshot; +struct CapsSnapshotBuilder; + +struct DefaultFramebufferInfo; +struct DefaultFramebufferInfoBuilder; + +struct SurfaceOp; +struct SurfaceOpBuilder; + +struct SurfaceReply; +struct SurfaceReplyBuilder; + +struct ResyncRequest; +struct ResyncRequestBuilder; + +struct ResyncDone; +struct ResyncDoneBuilder; + +struct AuxRequest; +struct AuxRequestBuilder; + +struct Fatal; +struct FatalBuilder; + +struct LogLine; +struct LogLineBuilder; + +struct CtrlEnvelope; +struct CtrlEnvelopeBuilder; + +enum class SegmentKind : uint8_t { + None = 0, + Cmd = 1, + Stage = 2, + Reply = 3, + Event = 4, + Shadow = 5, + Adopt = 6, + MIN = None, + MAX = Adopt +}; + +inline const SegmentKind (&EnumValuesSegmentKind())[7] { + static const SegmentKind values[] = { + SegmentKind::None, + SegmentKind::Cmd, + SegmentKind::Stage, + SegmentKind::Reply, + SegmentKind::Event, + SegmentKind::Shadow, + SegmentKind::Adopt + }; + return values; +} + +inline const char * const *EnumNamesSegmentKind() { + static const char * const names[8] = { + "None", + "Cmd", + "Stage", + "Reply", + "Event", + "Shadow", + "Adopt", + nullptr + }; + return names; +} + +inline const char *EnumNameSegmentKind(SegmentKind e) { + if (::flatbuffers::IsOutRange(e, SegmentKind::None, SegmentKind::Adopt)) return ""; + const size_t index = static_cast(e); + return EnumNamesSegmentKind()[index]; +} + +enum class SurfaceOpKind : uint8_t { + None = 0, + InitializeDisplay = 1, + CreateWindowSurface = 2, + CreatePbufferSurface = 3, + ResizeWindowSurface = 4, + ReleaseSurface = 5, + MakeCurrent = 6, + ReleaseCurrent = 7, + MIN = None, + MAX = ReleaseCurrent +}; + +inline const SurfaceOpKind (&EnumValuesSurfaceOpKind())[8] { + static const SurfaceOpKind values[] = { + SurfaceOpKind::None, + SurfaceOpKind::InitializeDisplay, + SurfaceOpKind::CreateWindowSurface, + SurfaceOpKind::CreatePbufferSurface, + SurfaceOpKind::ResizeWindowSurface, + SurfaceOpKind::ReleaseSurface, + SurfaceOpKind::MakeCurrent, + SurfaceOpKind::ReleaseCurrent + }; + return values; +} + +inline const char * const *EnumNamesSurfaceOpKind() { + static const char * const names[9] = { + "None", + "InitializeDisplay", + "CreateWindowSurface", + "CreatePbufferSurface", + "ResizeWindowSurface", + "ReleaseSurface", + "MakeCurrent", + "ReleaseCurrent", + nullptr + }; + return names; +} + +inline const char *EnumNameSurfaceOpKind(SurfaceOpKind e) { + if (::flatbuffers::IsOutRange(e, SurfaceOpKind::None, SurfaceOpKind::ReleaseCurrent)) return ""; + const size_t index = static_cast(e); + return EnumNamesSurfaceOpKind()[index]; +} + +enum class WindowKind : uint8_t { + None = 0, + AndroidNativeWindow = 1, + X11 = 2, + Win32Hwnd = 3, + Surfaceless = 4, + Pbuffer = 5, + MIN = None, + MAX = Pbuffer +}; + +inline const WindowKind (&EnumValuesWindowKind())[6] { + static const WindowKind values[] = { + WindowKind::None, + WindowKind::AndroidNativeWindow, + WindowKind::X11, + WindowKind::Win32Hwnd, + WindowKind::Surfaceless, + WindowKind::Pbuffer + }; + return values; +} + +inline const char * const *EnumNamesWindowKind() { + static const char * const names[7] = { + "None", + "AndroidNativeWindow", + "X11", + "Win32Hwnd", + "Surfaceless", + "Pbuffer", + nullptr + }; + return names; +} + +inline const char *EnumNameWindowKind(WindowKind e) { + if (::flatbuffers::IsOutRange(e, WindowKind::None, WindowKind::Pbuffer)) return ""; + const size_t index = static_cast(e); + return EnumNamesWindowKind()[index]; +} + +enum class AuxRequestKind : uint8_t { + None = 0, + FenceClientWait = 1, + QueryResult = 2, + ScalarGet = 3, + MIN = None, + MAX = ScalarGet +}; + +inline const AuxRequestKind (&EnumValuesAuxRequestKind())[4] { + static const AuxRequestKind values[] = { + AuxRequestKind::None, + AuxRequestKind::FenceClientWait, + AuxRequestKind::QueryResult, + AuxRequestKind::ScalarGet + }; + return values; +} + +inline const char * const *EnumNamesAuxRequestKind() { + static const char * const names[5] = { + "None", + "FenceClientWait", + "QueryResult", + "ScalarGet", + nullptr + }; + return names; +} + +inline const char *EnumNameAuxRequestKind(AuxRequestKind e) { + if (::flatbuffers::IsOutRange(e, AuxRequestKind::None, AuxRequestKind::ScalarGet)) return ""; + const size_t index = static_cast(e); + return EnumNamesAuxRequestKind()[index]; +} + +enum class FatalCode : uint32_t { + None = 0, + ProtocolCorruption = 1, + RingOverrun = 2, + SegmentMismatch = 3, + DeviceLost = 4, + ServerCrashed = 5, + AbiMismatch = 6, + MIN = None, + MAX = AbiMismatch +}; + +inline const FatalCode (&EnumValuesFatalCode())[7] { + static const FatalCode values[] = { + FatalCode::None, + FatalCode::ProtocolCorruption, + FatalCode::RingOverrun, + FatalCode::SegmentMismatch, + FatalCode::DeviceLost, + FatalCode::ServerCrashed, + FatalCode::AbiMismatch + }; + return values; +} + +inline const char * const *EnumNamesFatalCode() { + static const char * const names[8] = { + "None", + "ProtocolCorruption", + "RingOverrun", + "SegmentMismatch", + "DeviceLost", + "ServerCrashed", + "AbiMismatch", + nullptr + }; + return names; +} + +inline const char *EnumNameFatalCode(FatalCode e) { + if (::flatbuffers::IsOutRange(e, FatalCode::None, FatalCode::AbiMismatch)) return ""; + const size_t index = static_cast(e); + return EnumNamesFatalCode()[index]; +} + +enum class LogLevel : uint8_t { + Debug = 0, + Info = 1, + Warn = 2, + Error = 3, + Fatal = 4, + MIN = Debug, + MAX = Fatal +}; + +inline const LogLevel (&EnumValuesLogLevel())[5] { + static const LogLevel values[] = { + LogLevel::Debug, + LogLevel::Info, + LogLevel::Warn, + LogLevel::Error, + LogLevel::Fatal + }; + return values; +} + +inline const char * const *EnumNamesLogLevel() { + static const char * const names[6] = { + "Debug", + "Info", + "Warn", + "Error", + "Fatal", + nullptr + }; + return names; +} + +inline const char *EnumNameLogLevel(LogLevel e) { + if (::flatbuffers::IsOutRange(e, LogLevel::Debug, LogLevel::Fatal)) return ""; + const size_t index = static_cast(e); + return EnumNamesLogLevel()[index]; +} + +enum class CtrlMsg : uint8_t { + NONE = 0, + Hello = 1, + Welcome = 2, + CapsSnapshot = 3, + SurfaceOp = 4, + SurfaceReply = 5, + ResyncRequest = 6, + ResyncDone = 7, + AuxRequest = 8, + Fatal = 9, + LogLine = 10, + MIN = NONE, + MAX = LogLine +}; + +inline const CtrlMsg (&EnumValuesCtrlMsg())[11] { + static const CtrlMsg values[] = { + CtrlMsg::NONE, + CtrlMsg::Hello, + CtrlMsg::Welcome, + CtrlMsg::CapsSnapshot, + CtrlMsg::SurfaceOp, + CtrlMsg::SurfaceReply, + CtrlMsg::ResyncRequest, + CtrlMsg::ResyncDone, + CtrlMsg::AuxRequest, + CtrlMsg::Fatal, + CtrlMsg::LogLine + }; + return values; +} + +inline const char * const *EnumNamesCtrlMsg() { + static const char * const names[12] = { + "NONE", + "Hello", + "Welcome", + "CapsSnapshot", + "SurfaceOp", + "SurfaceReply", + "ResyncRequest", + "ResyncDone", + "AuxRequest", + "Fatal", + "LogLine", + nullptr + }; + return names; +} + +inline const char *EnumNameCtrlMsg(CtrlMsg e) { + if (::flatbuffers::IsOutRange(e, CtrlMsg::NONE, CtrlMsg::LogLine)) return ""; + const size_t index = static_cast(e); + return EnumNamesCtrlMsg()[index]; +} + +template struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::NONE; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::Hello; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::Welcome; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::CapsSnapshot; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::SurfaceOp; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::SurfaceReply; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::ResyncRequest; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::ResyncDone; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::AuxRequest; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::Fatal; +}; + +template<> struct CtrlMsgTraits { + static const CtrlMsg enum_value = CtrlMsg::LogLine; +}; + +template +bool VerifyCtrlMsg(::flatbuffers::VerifierTemplate &verifier, const void *obj, CtrlMsg type); +template +bool VerifyCtrlMsgVector(::flatbuffers::VerifierTemplate &verifier, const ::flatbuffers::Vector<::flatbuffers::Offset> *values, const ::flatbuffers::Vector *types); + +struct SegmentRef FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SegmentRefBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ID = 4, + VT_KIND = 6, + VT_SIZEBYTES = 8, + VT_NAME = 10 + }; + uint32_t id() const { + return GetField(VT_ID, 0); + } + MobileGL::Wire::SegmentKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint64_t sizeBytes() const { + return GetField(VT_SIZEBYTES, 0); + } + const ::flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ID, 4) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_SIZEBYTES, 8) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + verifier.EndTable(); + } +}; + +struct SegmentRefBuilder { + typedef SegmentRef Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_id(uint32_t id) { + fbb_.AddElement(SegmentRef::VT_ID, id, 0); + } + void add_kind(MobileGL::Wire::SegmentKind kind) { + fbb_.AddElement(SegmentRef::VT_KIND, static_cast(kind), 0); + } + void add_sizeBytes(uint64_t sizeBytes) { + fbb_.AddElement(SegmentRef::VT_SIZEBYTES, sizeBytes, 0); + } + void add_name(::flatbuffers::Offset<::flatbuffers::String> name) { + fbb_.AddOffset(SegmentRef::VT_NAME, name); + } + explicit SegmentRefBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSegmentRef( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t id = 0, + MobileGL::Wire::SegmentKind kind = MobileGL::Wire::SegmentKind::None, + uint64_t sizeBytes = 0, + ::flatbuffers::Offset<::flatbuffers::String> name = 0) { + SegmentRefBuilder builder_(_fbb); + builder_.add_sizeBytes(sizeBytes); + builder_.add_name(name); + builder_.add_id(id); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct SegmentRef::Traits { + using type = SegmentRef; + static auto constexpr Create = CreateSegmentRef; +}; + +inline ::flatbuffers::Offset CreateSegmentRefDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t id = 0, + MobileGL::Wire::SegmentKind kind = MobileGL::Wire::SegmentKind::None, + uint64_t sizeBytes = 0, + const char *name = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return MobileGL::Wire::CreateSegmentRef( + _fbb, + id, + kind, + sizeBytes, + name__); +} + +struct Hello FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef HelloBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ABIMAJOR = 4, + VT_ABIMINOR = 6, + VT_BUILDFINGERPRINT = 8, + VT_BACKENDTYPE = 10, + VT_PID = 12, + VT_CONFIGBLOB = 14 + }; + uint32_t abiMajor() const { + return GetField(VT_ABIMAJOR, 0); + } + uint32_t abiMinor() const { + return GetField(VT_ABIMINOR, 0); + } + const ::flatbuffers::String *buildFingerprint() const { + return GetPointer(VT_BUILDFINGERPRINT); + } + uint32_t backendType() const { + return GetField(VT_BACKENDTYPE, 0); + } + uint32_t pid() const { + return GetField(VT_PID, 0); + } + const ::flatbuffers::Vector *configBlob() const { + return GetPointer *>(VT_CONFIGBLOB); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ABIMAJOR, 4) && + VerifyField(verifier, VT_ABIMINOR, 4) && + VerifyOffset(verifier, VT_BUILDFINGERPRINT) && + verifier.VerifyString(buildFingerprint()) && + VerifyField(verifier, VT_BACKENDTYPE, 4) && + VerifyField(verifier, VT_PID, 4) && + VerifyOffset(verifier, VT_CONFIGBLOB) && + verifier.VerifyVector(configBlob()) && + verifier.EndTable(); + } +}; + +struct HelloBuilder { + typedef Hello Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_abiMajor(uint32_t abiMajor) { + fbb_.AddElement(Hello::VT_ABIMAJOR, abiMajor, 0); + } + void add_abiMinor(uint32_t abiMinor) { + fbb_.AddElement(Hello::VT_ABIMINOR, abiMinor, 0); + } + void add_buildFingerprint(::flatbuffers::Offset<::flatbuffers::String> buildFingerprint) { + fbb_.AddOffset(Hello::VT_BUILDFINGERPRINT, buildFingerprint); + } + void add_backendType(uint32_t backendType) { + fbb_.AddElement(Hello::VT_BACKENDTYPE, backendType, 0); + } + void add_pid(uint32_t pid) { + fbb_.AddElement(Hello::VT_PID, pid, 0); + } + void add_configBlob(::flatbuffers::Offset<::flatbuffers::Vector> configBlob) { + fbb_.AddOffset(Hello::VT_CONFIGBLOB, configBlob); + } + explicit HelloBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateHello( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t abiMajor = 0, + uint32_t abiMinor = 0, + ::flatbuffers::Offset<::flatbuffers::String> buildFingerprint = 0, + uint32_t backendType = 0, + uint32_t pid = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> configBlob = 0) { + HelloBuilder builder_(_fbb); + builder_.add_configBlob(configBlob); + builder_.add_pid(pid); + builder_.add_backendType(backendType); + builder_.add_buildFingerprint(buildFingerprint); + builder_.add_abiMinor(abiMinor); + builder_.add_abiMajor(abiMajor); + return builder_.Finish(); +} + +struct Hello::Traits { + using type = Hello; + static auto constexpr Create = CreateHello; +}; + +inline ::flatbuffers::Offset CreateHelloDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t abiMajor = 0, + uint32_t abiMinor = 0, + const char *buildFingerprint = nullptr, + uint32_t backendType = 0, + uint32_t pid = 0, + const std::vector *configBlob = nullptr) { + auto buildFingerprint__ = buildFingerprint ? _fbb.CreateString(buildFingerprint) : 0; + auto configBlob__ = configBlob ? _fbb.CreateVector(*configBlob) : 0; + return MobileGL::Wire::CreateHello( + _fbb, + abiMajor, + abiMinor, + buildFingerprint__, + backendType, + pid, + configBlob__); +} + +struct Welcome FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef WelcomeBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ABIMAJOR = 4, + VT_ABIMINOR = 6, + VT_SERVERPID = 8, + VT_CMDRING = 10, + VT_STAGERING = 12, + VT_REPLYPOOL = 14, + VT_EVENTRING = 16 + }; + uint32_t abiMajor() const { + return GetField(VT_ABIMAJOR, 0); + } + uint32_t abiMinor() const { + return GetField(VT_ABIMINOR, 0); + } + uint32_t serverPid() const { + return GetField(VT_SERVERPID, 0); + } + const MobileGL::Wire::SegmentRef *cmdRing() const { + return GetPointer(VT_CMDRING); + } + const MobileGL::Wire::SegmentRef *stageRing() const { + return GetPointer(VT_STAGERING); + } + const MobileGL::Wire::SegmentRef *replyPool() const { + return GetPointer(VT_REPLYPOOL); + } + const MobileGL::Wire::SegmentRef *eventRing() const { + return GetPointer(VT_EVENTRING); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ABIMAJOR, 4) && + VerifyField(verifier, VT_ABIMINOR, 4) && + VerifyField(verifier, VT_SERVERPID, 4) && + VerifyOffset(verifier, VT_CMDRING) && + verifier.VerifyTable(cmdRing()) && + VerifyOffset(verifier, VT_STAGERING) && + verifier.VerifyTable(stageRing()) && + VerifyOffset(verifier, VT_REPLYPOOL) && + verifier.VerifyTable(replyPool()) && + VerifyOffset(verifier, VT_EVENTRING) && + verifier.VerifyTable(eventRing()) && + verifier.EndTable(); + } +}; + +struct WelcomeBuilder { + typedef Welcome Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_abiMajor(uint32_t abiMajor) { + fbb_.AddElement(Welcome::VT_ABIMAJOR, abiMajor, 0); + } + void add_abiMinor(uint32_t abiMinor) { + fbb_.AddElement(Welcome::VT_ABIMINOR, abiMinor, 0); + } + void add_serverPid(uint32_t serverPid) { + fbb_.AddElement(Welcome::VT_SERVERPID, serverPid, 0); + } + void add_cmdRing(::flatbuffers::Offset cmdRing) { + fbb_.AddOffset(Welcome::VT_CMDRING, cmdRing); + } + void add_stageRing(::flatbuffers::Offset stageRing) { + fbb_.AddOffset(Welcome::VT_STAGERING, stageRing); + } + void add_replyPool(::flatbuffers::Offset replyPool) { + fbb_.AddOffset(Welcome::VT_REPLYPOOL, replyPool); + } + void add_eventRing(::flatbuffers::Offset eventRing) { + fbb_.AddOffset(Welcome::VT_EVENTRING, eventRing); + } + explicit WelcomeBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateWelcome( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t abiMajor = 0, + uint32_t abiMinor = 0, + uint32_t serverPid = 0, + ::flatbuffers::Offset cmdRing = 0, + ::flatbuffers::Offset stageRing = 0, + ::flatbuffers::Offset replyPool = 0, + ::flatbuffers::Offset eventRing = 0) { + WelcomeBuilder builder_(_fbb); + builder_.add_eventRing(eventRing); + builder_.add_replyPool(replyPool); + builder_.add_stageRing(stageRing); + builder_.add_cmdRing(cmdRing); + builder_.add_serverPid(serverPid); + builder_.add_abiMinor(abiMinor); + builder_.add_abiMajor(abiMajor); + return builder_.Finish(); +} + +struct Welcome::Traits { + using type = Welcome; + static auto constexpr Create = CreateWelcome; +}; + +struct CapsSnapshot FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef CapsSnapshotBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DYNAMICPARAMETERS = 4, + VT_RENDERERINFO = 6, + VT_FORMATCAPS = 8, + VT_EXTENSIONS = 10, + VT_APIVERSION = 12, + VT_MAXCOMPUTEWORKGROUPCOUNT = 14, + VT_MAXCOMPUTEWORKGROUPSIZE = 16, + VT_TABLESLOTMASK = 18, + VT_PREFERSCPUXFBPRIMITIVEACCOUNTING = 20 + }; + const ::flatbuffers::Vector *dynamicParameters() const { + return GetPointer *>(VT_DYNAMICPARAMETERS); + } + const ::flatbuffers::Vector *rendererInfo() const { + return GetPointer *>(VT_RENDERERINFO); + } + const ::flatbuffers::Vector *formatCaps() const { + return GetPointer *>(VT_FORMATCAPS); + } + const ::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>> *extensions() const { + return GetPointer> *>(VT_EXTENSIONS); + } + const ::flatbuffers::String *apiVersion() const { + return GetPointer(VT_APIVERSION); + } + const ::flatbuffers::Vector *maxComputeWorkGroupCount() const { + return GetPointer *>(VT_MAXCOMPUTEWORKGROUPCOUNT); + } + const ::flatbuffers::Vector *maxComputeWorkGroupSize() const { + return GetPointer *>(VT_MAXCOMPUTEWORKGROUPSIZE); + } + uint64_t tableSlotMask() const { + return GetField(VT_TABLESLOTMASK, 0); + } + bool prefersCpuXfbPrimitiveAccounting() const { + return GetField(VT_PREFERSCPUXFBPRIMITIVEACCOUNTING, 0) != 0; + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_DYNAMICPARAMETERS) && + verifier.VerifyVector(dynamicParameters()) && + VerifyOffset(verifier, VT_RENDERERINFO) && + verifier.VerifyVector(rendererInfo()) && + VerifyOffset(verifier, VT_FORMATCAPS) && + verifier.VerifyVector(formatCaps()) && + VerifyOffset(verifier, VT_EXTENSIONS) && + verifier.VerifyVector(extensions()) && + verifier.VerifyVectorOfStrings(extensions()) && + VerifyOffset(verifier, VT_APIVERSION) && + verifier.VerifyString(apiVersion()) && + VerifyOffset(verifier, VT_MAXCOMPUTEWORKGROUPCOUNT) && + verifier.VerifyVector(maxComputeWorkGroupCount()) && + VerifyOffset(verifier, VT_MAXCOMPUTEWORKGROUPSIZE) && + verifier.VerifyVector(maxComputeWorkGroupSize()) && + VerifyField(verifier, VT_TABLESLOTMASK, 8) && + VerifyField(verifier, VT_PREFERSCPUXFBPRIMITIVEACCOUNTING, 1) && + verifier.EndTable(); + } +}; + +struct CapsSnapshotBuilder { + typedef CapsSnapshot Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_dynamicParameters(::flatbuffers::Offset<::flatbuffers::Vector> dynamicParameters) { + fbb_.AddOffset(CapsSnapshot::VT_DYNAMICPARAMETERS, dynamicParameters); + } + void add_rendererInfo(::flatbuffers::Offset<::flatbuffers::Vector> rendererInfo) { + fbb_.AddOffset(CapsSnapshot::VT_RENDERERINFO, rendererInfo); + } + void add_formatCaps(::flatbuffers::Offset<::flatbuffers::Vector> formatCaps) { + fbb_.AddOffset(CapsSnapshot::VT_FORMATCAPS, formatCaps); + } + void add_extensions(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> extensions) { + fbb_.AddOffset(CapsSnapshot::VT_EXTENSIONS, extensions); + } + void add_apiVersion(::flatbuffers::Offset<::flatbuffers::String> apiVersion) { + fbb_.AddOffset(CapsSnapshot::VT_APIVERSION, apiVersion); + } + void add_maxComputeWorkGroupCount(::flatbuffers::Offset<::flatbuffers::Vector> maxComputeWorkGroupCount) { + fbb_.AddOffset(CapsSnapshot::VT_MAXCOMPUTEWORKGROUPCOUNT, maxComputeWorkGroupCount); + } + void add_maxComputeWorkGroupSize(::flatbuffers::Offset<::flatbuffers::Vector> maxComputeWorkGroupSize) { + fbb_.AddOffset(CapsSnapshot::VT_MAXCOMPUTEWORKGROUPSIZE, maxComputeWorkGroupSize); + } + void add_tableSlotMask(uint64_t tableSlotMask) { + fbb_.AddElement(CapsSnapshot::VT_TABLESLOTMASK, tableSlotMask, 0); + } + void add_prefersCpuXfbPrimitiveAccounting(bool prefersCpuXfbPrimitiveAccounting) { + fbb_.AddElement(CapsSnapshot::VT_PREFERSCPUXFBPRIMITIVEACCOUNTING, static_cast(prefersCpuXfbPrimitiveAccounting), 0); + } + explicit CapsSnapshotBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateCapsSnapshot( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset<::flatbuffers::Vector> dynamicParameters = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> rendererInfo = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> formatCaps = 0, + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<::flatbuffers::String>>> extensions = 0, + ::flatbuffers::Offset<::flatbuffers::String> apiVersion = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> maxComputeWorkGroupCount = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> maxComputeWorkGroupSize = 0, + uint64_t tableSlotMask = 0, + bool prefersCpuXfbPrimitiveAccounting = false) { + CapsSnapshotBuilder builder_(_fbb); + builder_.add_tableSlotMask(tableSlotMask); + builder_.add_maxComputeWorkGroupSize(maxComputeWorkGroupSize); + builder_.add_maxComputeWorkGroupCount(maxComputeWorkGroupCount); + builder_.add_apiVersion(apiVersion); + builder_.add_extensions(extensions); + builder_.add_formatCaps(formatCaps); + builder_.add_rendererInfo(rendererInfo); + builder_.add_dynamicParameters(dynamicParameters); + builder_.add_prefersCpuXfbPrimitiveAccounting(prefersCpuXfbPrimitiveAccounting); + return builder_.Finish(); +} + +struct CapsSnapshot::Traits { + using type = CapsSnapshot; + static auto constexpr Create = CreateCapsSnapshot; +}; + +inline ::flatbuffers::Offset CreateCapsSnapshotDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *dynamicParameters = nullptr, + const std::vector *rendererInfo = nullptr, + const std::vector *formatCaps = nullptr, + const std::vector<::flatbuffers::Offset<::flatbuffers::String>> *extensions = nullptr, + const char *apiVersion = nullptr, + const std::vector *maxComputeWorkGroupCount = nullptr, + const std::vector *maxComputeWorkGroupSize = nullptr, + uint64_t tableSlotMask = 0, + bool prefersCpuXfbPrimitiveAccounting = false) { + auto dynamicParameters__ = dynamicParameters ? _fbb.CreateVector(*dynamicParameters) : 0; + auto rendererInfo__ = rendererInfo ? _fbb.CreateVector(*rendererInfo) : 0; + auto formatCaps__ = formatCaps ? _fbb.CreateVector(*formatCaps) : 0; + auto extensions__ = extensions ? _fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::String>>(*extensions) : 0; + auto apiVersion__ = apiVersion ? _fbb.CreateString(apiVersion) : 0; + auto maxComputeWorkGroupCount__ = maxComputeWorkGroupCount ? _fbb.CreateVector(*maxComputeWorkGroupCount) : 0; + auto maxComputeWorkGroupSize__ = maxComputeWorkGroupSize ? _fbb.CreateVector(*maxComputeWorkGroupSize) : 0; + return MobileGL::Wire::CreateCapsSnapshot( + _fbb, + dynamicParameters__, + rendererInfo__, + formatCaps__, + extensions__, + apiVersion__, + maxComputeWorkGroupCount__, + maxComputeWorkGroupSize__, + tableSlotMask, + prefersCpuXfbPrimitiveAccounting); +} + +struct DefaultFramebufferInfo FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef DefaultFramebufferInfoBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_WIDTH = 4, + VT_HEIGHT = 6, + VT_COLORFORMAT = 8, + VT_DEPTHFORMAT = 10, + VT_STENCILFORMAT = 12 + }; + int32_t width() const { + return GetField(VT_WIDTH, 0); + } + int32_t height() const { + return GetField(VT_HEIGHT, 0); + } + uint32_t colorFormat() const { + return GetField(VT_COLORFORMAT, 0); + } + uint32_t depthFormat() const { + return GetField(VT_DEPTHFORMAT, 0); + } + uint32_t stencilFormat() const { + return GetField(VT_STENCILFORMAT, 0); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_WIDTH, 4) && + VerifyField(verifier, VT_HEIGHT, 4) && + VerifyField(verifier, VT_COLORFORMAT, 4) && + VerifyField(verifier, VT_DEPTHFORMAT, 4) && + VerifyField(verifier, VT_STENCILFORMAT, 4) && + verifier.EndTable(); + } +}; + +struct DefaultFramebufferInfoBuilder { + typedef DefaultFramebufferInfo Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_width(int32_t width) { + fbb_.AddElement(DefaultFramebufferInfo::VT_WIDTH, width, 0); + } + void add_height(int32_t height) { + fbb_.AddElement(DefaultFramebufferInfo::VT_HEIGHT, height, 0); + } + void add_colorFormat(uint32_t colorFormat) { + fbb_.AddElement(DefaultFramebufferInfo::VT_COLORFORMAT, colorFormat, 0); + } + void add_depthFormat(uint32_t depthFormat) { + fbb_.AddElement(DefaultFramebufferInfo::VT_DEPTHFORMAT, depthFormat, 0); + } + void add_stencilFormat(uint32_t stencilFormat) { + fbb_.AddElement(DefaultFramebufferInfo::VT_STENCILFORMAT, stencilFormat, 0); + } + explicit DefaultFramebufferInfoBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateDefaultFramebufferInfo( + ::flatbuffers::FlatBufferBuilder &_fbb, + int32_t width = 0, + int32_t height = 0, + uint32_t colorFormat = 0, + uint32_t depthFormat = 0, + uint32_t stencilFormat = 0) { + DefaultFramebufferInfoBuilder builder_(_fbb); + builder_.add_stencilFormat(stencilFormat); + builder_.add_depthFormat(depthFormat); + builder_.add_colorFormat(colorFormat); + builder_.add_height(height); + builder_.add_width(width); + return builder_.Finish(); +} + +struct DefaultFramebufferInfo::Traits { + using type = DefaultFramebufferInfo; + static auto constexpr Create = CreateDefaultFramebufferInfo; +}; + +struct SurfaceOp FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SurfaceOpBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SEQ = 4, + VT_KIND = 6, + VT_DISPLAY = 8, + VT_SURFACE = 10, + VT_WINDOWKIND = 12, + VT_NATIVETOKEN = 14, + VT_WIDTH = 16, + VT_HEIGHT = 18, + VT_SWAPINTERVAL = 20 + }; + uint64_t seq() const { + return GetField(VT_SEQ, 0); + } + MobileGL::Wire::SurfaceOpKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + uint64_t display() const { + return GetField(VT_DISPLAY, 0); + } + uint64_t surface() const { + return GetField(VT_SURFACE, 0); + } + MobileGL::Wire::WindowKind windowKind() const { + return static_cast(GetField(VT_WINDOWKIND, 0)); + } + uint64_t nativeToken() const { + return GetField(VT_NATIVETOKEN, 0); + } + int32_t width() const { + return GetField(VT_WIDTH, 0); + } + int32_t height() const { + return GetField(VT_HEIGHT, 0); + } + int32_t swapInterval() const { + return GetField(VT_SWAPINTERVAL, 0); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SEQ, 8) && + VerifyField(verifier, VT_KIND, 1) && + VerifyField(verifier, VT_DISPLAY, 8) && + VerifyField(verifier, VT_SURFACE, 8) && + VerifyField(verifier, VT_WINDOWKIND, 1) && + VerifyField(verifier, VT_NATIVETOKEN, 8) && + VerifyField(verifier, VT_WIDTH, 4) && + VerifyField(verifier, VT_HEIGHT, 4) && + VerifyField(verifier, VT_SWAPINTERVAL, 4) && + verifier.EndTable(); + } +}; + +struct SurfaceOpBuilder { + typedef SurfaceOp Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_seq(uint64_t seq) { + fbb_.AddElement(SurfaceOp::VT_SEQ, seq, 0); + } + void add_kind(MobileGL::Wire::SurfaceOpKind kind) { + fbb_.AddElement(SurfaceOp::VT_KIND, static_cast(kind), 0); + } + void add_display(uint64_t display) { + fbb_.AddElement(SurfaceOp::VT_DISPLAY, display, 0); + } + void add_surface(uint64_t surface) { + fbb_.AddElement(SurfaceOp::VT_SURFACE, surface, 0); + } + void add_windowKind(MobileGL::Wire::WindowKind windowKind) { + fbb_.AddElement(SurfaceOp::VT_WINDOWKIND, static_cast(windowKind), 0); + } + void add_nativeToken(uint64_t nativeToken) { + fbb_.AddElement(SurfaceOp::VT_NATIVETOKEN, nativeToken, 0); + } + void add_width(int32_t width) { + fbb_.AddElement(SurfaceOp::VT_WIDTH, width, 0); + } + void add_height(int32_t height) { + fbb_.AddElement(SurfaceOp::VT_HEIGHT, height, 0); + } + void add_swapInterval(int32_t swapInterval) { + fbb_.AddElement(SurfaceOp::VT_SWAPINTERVAL, swapInterval, 0); + } + explicit SurfaceOpBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSurfaceOp( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint64_t seq = 0, + MobileGL::Wire::SurfaceOpKind kind = MobileGL::Wire::SurfaceOpKind::None, + uint64_t display = 0, + uint64_t surface = 0, + MobileGL::Wire::WindowKind windowKind = MobileGL::Wire::WindowKind::None, + uint64_t nativeToken = 0, + int32_t width = 0, + int32_t height = 0, + int32_t swapInterval = 0) { + SurfaceOpBuilder builder_(_fbb); + builder_.add_nativeToken(nativeToken); + builder_.add_surface(surface); + builder_.add_display(display); + builder_.add_seq(seq); + builder_.add_swapInterval(swapInterval); + builder_.add_height(height); + builder_.add_width(width); + builder_.add_windowKind(windowKind); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct SurfaceOp::Traits { + using type = SurfaceOp; + static auto constexpr Create = CreateSurfaceOp; +}; + +struct SurfaceReply FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef SurfaceReplyBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SEQ = 4, + VT_OK = 6, + VT_EGLMAJOR = 8, + VT_EGLMINOR = 10, + VT_DEFAULTFB = 12 + }; + uint64_t seq() const { + return GetField(VT_SEQ, 0); + } + bool ok() const { + return GetField(VT_OK, 0) != 0; + } + int32_t eglMajor() const { + return GetField(VT_EGLMAJOR, 0); + } + int32_t eglMinor() const { + return GetField(VT_EGLMINOR, 0); + } + const MobileGL::Wire::DefaultFramebufferInfo *defaultFb() const { + return GetPointer(VT_DEFAULTFB); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SEQ, 8) && + VerifyField(verifier, VT_OK, 1) && + VerifyField(verifier, VT_EGLMAJOR, 4) && + VerifyField(verifier, VT_EGLMINOR, 4) && + VerifyOffset(verifier, VT_DEFAULTFB) && + verifier.VerifyTable(defaultFb()) && + verifier.EndTable(); + } +}; + +struct SurfaceReplyBuilder { + typedef SurfaceReply Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_seq(uint64_t seq) { + fbb_.AddElement(SurfaceReply::VT_SEQ, seq, 0); + } + void add_ok(bool ok) { + fbb_.AddElement(SurfaceReply::VT_OK, static_cast(ok), 0); + } + void add_eglMajor(int32_t eglMajor) { + fbb_.AddElement(SurfaceReply::VT_EGLMAJOR, eglMajor, 0); + } + void add_eglMinor(int32_t eglMinor) { + fbb_.AddElement(SurfaceReply::VT_EGLMINOR, eglMinor, 0); + } + void add_defaultFb(::flatbuffers::Offset defaultFb) { + fbb_.AddOffset(SurfaceReply::VT_DEFAULTFB, defaultFb); + } + explicit SurfaceReplyBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateSurfaceReply( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint64_t seq = 0, + bool ok = false, + int32_t eglMajor = 0, + int32_t eglMinor = 0, + ::flatbuffers::Offset defaultFb = 0) { + SurfaceReplyBuilder builder_(_fbb); + builder_.add_seq(seq); + builder_.add_defaultFb(defaultFb); + builder_.add_eglMinor(eglMinor); + builder_.add_eglMajor(eglMajor); + builder_.add_ok(ok); + return builder_.Finish(); +} + +struct SurfaceReply::Traits { + using type = SurfaceReply; + static auto constexpr Create = CreateSurfaceReply; +}; + +struct ResyncRequest FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ResyncRequestBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SERVEREPOCH = 4 + }; + uint32_t serverEpoch() const { + return GetField(VT_SERVEREPOCH, 0); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SERVEREPOCH, 4) && + verifier.EndTable(); + } +}; + +struct ResyncRequestBuilder { + typedef ResyncRequest Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_serverEpoch(uint32_t serverEpoch) { + fbb_.AddElement(ResyncRequest::VT_SERVEREPOCH, serverEpoch, 0); + } + explicit ResyncRequestBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateResyncRequest( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t serverEpoch = 0) { + ResyncRequestBuilder builder_(_fbb); + builder_.add_serverEpoch(serverEpoch); + return builder_.Finish(); +} + +struct ResyncRequest::Traits { + using type = ResyncRequest; + static auto constexpr Create = CreateResyncRequest; +}; + +struct ResyncDone FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef ResyncDoneBuilder Builder; + struct Traits; + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } +}; + +struct ResyncDoneBuilder { + typedef ResyncDone Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + explicit ResyncDoneBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateResyncDone( + ::flatbuffers::FlatBufferBuilder &_fbb) { + ResyncDoneBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ResyncDone::Traits { + using type = ResyncDone; + static auto constexpr Create = CreateResyncDone; +}; + +struct AuxRequest FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AuxRequestBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SEQ = 4, + VT_KIND = 6, + VT_PAYLOAD = 8 + }; + uint64_t seq() const { + return GetField(VT_SEQ, 0); + } + MobileGL::Wire::AuxRequestKind kind() const { + return static_cast(GetField(VT_KIND, 0)); + } + const ::flatbuffers::Vector *payload() const { + return GetPointer *>(VT_PAYLOAD); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SEQ, 8) && + VerifyField(verifier, VT_KIND, 1) && + VerifyOffset(verifier, VT_PAYLOAD) && + verifier.VerifyVector(payload()) && + verifier.EndTable(); + } +}; + +struct AuxRequestBuilder { + typedef AuxRequest Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_seq(uint64_t seq) { + fbb_.AddElement(AuxRequest::VT_SEQ, seq, 0); + } + void add_kind(MobileGL::Wire::AuxRequestKind kind) { + fbb_.AddElement(AuxRequest::VT_KIND, static_cast(kind), 0); + } + void add_payload(::flatbuffers::Offset<::flatbuffers::Vector> payload) { + fbb_.AddOffset(AuxRequest::VT_PAYLOAD, payload); + } + explicit AuxRequestBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAuxRequest( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint64_t seq = 0, + MobileGL::Wire::AuxRequestKind kind = MobileGL::Wire::AuxRequestKind::None, + ::flatbuffers::Offset<::flatbuffers::Vector> payload = 0) { + AuxRequestBuilder builder_(_fbb); + builder_.add_seq(seq); + builder_.add_payload(payload); + builder_.add_kind(kind); + return builder_.Finish(); +} + +struct AuxRequest::Traits { + using type = AuxRequest; + static auto constexpr Create = CreateAuxRequest; +}; + +inline ::flatbuffers::Offset CreateAuxRequestDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint64_t seq = 0, + MobileGL::Wire::AuxRequestKind kind = MobileGL::Wire::AuxRequestKind::None, + const std::vector *payload = nullptr) { + auto payload__ = payload ? _fbb.CreateVector(*payload) : 0; + return MobileGL::Wire::CreateAuxRequest( + _fbb, + seq, + kind, + payload__); +} + +struct Fatal FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef FatalBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_CODE = 4, + VT_MESSAGE = 6 + }; + MobileGL::Wire::FatalCode code() const { + return static_cast(GetField(VT_CODE, 0)); + } + const ::flatbuffers::String *message() const { + return GetPointer(VT_MESSAGE); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_CODE, 4) && + VerifyOffset(verifier, VT_MESSAGE) && + verifier.VerifyString(message()) && + verifier.EndTable(); + } +}; + +struct FatalBuilder { + typedef Fatal Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_code(MobileGL::Wire::FatalCode code) { + fbb_.AddElement(Fatal::VT_CODE, static_cast(code), 0); + } + void add_message(::flatbuffers::Offset<::flatbuffers::String> message) { + fbb_.AddOffset(Fatal::VT_MESSAGE, message); + } + explicit FatalBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateFatal( + ::flatbuffers::FlatBufferBuilder &_fbb, + MobileGL::Wire::FatalCode code = MobileGL::Wire::FatalCode::None, + ::flatbuffers::Offset<::flatbuffers::String> message = 0) { + FatalBuilder builder_(_fbb); + builder_.add_message(message); + builder_.add_code(code); + return builder_.Finish(); +} + +struct Fatal::Traits { + using type = Fatal; + static auto constexpr Create = CreateFatal; +}; + +inline ::flatbuffers::Offset CreateFatalDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + MobileGL::Wire::FatalCode code = MobileGL::Wire::FatalCode::None, + const char *message = nullptr) { + auto message__ = message ? _fbb.CreateString(message) : 0; + return MobileGL::Wire::CreateFatal( + _fbb, + code, + message__); +} + +struct LogLine FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef LogLineBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_LEVEL = 4, + VT_TEXT = 6 + }; + MobileGL::Wire::LogLevel level() const { + return static_cast(GetField(VT_LEVEL, 0)); + } + const ::flatbuffers::String *text() const { + return GetPointer(VT_TEXT); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_LEVEL, 1) && + VerifyOffset(verifier, VT_TEXT) && + verifier.VerifyString(text()) && + verifier.EndTable(); + } +}; + +struct LogLineBuilder { + typedef LogLine Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_level(MobileGL::Wire::LogLevel level) { + fbb_.AddElement(LogLine::VT_LEVEL, static_cast(level), 0); + } + void add_text(::flatbuffers::Offset<::flatbuffers::String> text) { + fbb_.AddOffset(LogLine::VT_TEXT, text); + } + explicit LogLineBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateLogLine( + ::flatbuffers::FlatBufferBuilder &_fbb, + MobileGL::Wire::LogLevel level = MobileGL::Wire::LogLevel::Debug, + ::flatbuffers::Offset<::flatbuffers::String> text = 0) { + LogLineBuilder builder_(_fbb); + builder_.add_text(text); + builder_.add_level(level); + return builder_.Finish(); +} + +struct LogLine::Traits { + using type = LogLine; + static auto constexpr Create = CreateLogLine; +}; + +inline ::flatbuffers::Offset CreateLogLineDirect( + ::flatbuffers::FlatBufferBuilder &_fbb, + MobileGL::Wire::LogLevel level = MobileGL::Wire::LogLevel::Debug, + const char *text = nullptr) { + auto text__ = text ? _fbb.CreateString(text) : 0; + return MobileGL::Wire::CreateLogLine( + _fbb, + level, + text__); +} + +struct CtrlEnvelope FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef CtrlEnvelopeBuilder Builder; + struct Traits; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_MSG_TYPE = 4, + VT_MSG = 6 + }; + MobileGL::Wire::CtrlMsg msg_type() const { + return static_cast(GetField(VT_MSG_TYPE, 0)); + } + const void *msg() const { + return GetPointer(VT_MSG); + } + template const T *msg_as() const; + const MobileGL::Wire::Hello *msg_as_Hello() const { + return msg_type() == MobileGL::Wire::CtrlMsg::Hello ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::Welcome *msg_as_Welcome() const { + return msg_type() == MobileGL::Wire::CtrlMsg::Welcome ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::CapsSnapshot *msg_as_CapsSnapshot() const { + return msg_type() == MobileGL::Wire::CtrlMsg::CapsSnapshot ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::SurfaceOp *msg_as_SurfaceOp() const { + return msg_type() == MobileGL::Wire::CtrlMsg::SurfaceOp ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::SurfaceReply *msg_as_SurfaceReply() const { + return msg_type() == MobileGL::Wire::CtrlMsg::SurfaceReply ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::ResyncRequest *msg_as_ResyncRequest() const { + return msg_type() == MobileGL::Wire::CtrlMsg::ResyncRequest ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::ResyncDone *msg_as_ResyncDone() const { + return msg_type() == MobileGL::Wire::CtrlMsg::ResyncDone ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::AuxRequest *msg_as_AuxRequest() const { + return msg_type() == MobileGL::Wire::CtrlMsg::AuxRequest ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::Fatal *msg_as_Fatal() const { + return msg_type() == MobileGL::Wire::CtrlMsg::Fatal ? static_cast(msg()) : nullptr; + } + const MobileGL::Wire::LogLine *msg_as_LogLine() const { + return msg_type() == MobileGL::Wire::CtrlMsg::LogLine ? static_cast(msg()) : nullptr; + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MSG_TYPE, 1) && + VerifyOffset(verifier, VT_MSG) && + VerifyCtrlMsg(verifier, msg(), msg_type()) && + verifier.EndTable(); + } +}; + +template<> inline const MobileGL::Wire::Hello *CtrlEnvelope::msg_as() const { + return msg_as_Hello(); +} + +template<> inline const MobileGL::Wire::Welcome *CtrlEnvelope::msg_as() const { + return msg_as_Welcome(); +} + +template<> inline const MobileGL::Wire::CapsSnapshot *CtrlEnvelope::msg_as() const { + return msg_as_CapsSnapshot(); +} + +template<> inline const MobileGL::Wire::SurfaceOp *CtrlEnvelope::msg_as() const { + return msg_as_SurfaceOp(); +} + +template<> inline const MobileGL::Wire::SurfaceReply *CtrlEnvelope::msg_as() const { + return msg_as_SurfaceReply(); +} + +template<> inline const MobileGL::Wire::ResyncRequest *CtrlEnvelope::msg_as() const { + return msg_as_ResyncRequest(); +} + +template<> inline const MobileGL::Wire::ResyncDone *CtrlEnvelope::msg_as() const { + return msg_as_ResyncDone(); +} + +template<> inline const MobileGL::Wire::AuxRequest *CtrlEnvelope::msg_as() const { + return msg_as_AuxRequest(); +} + +template<> inline const MobileGL::Wire::Fatal *CtrlEnvelope::msg_as() const { + return msg_as_Fatal(); +} + +template<> inline const MobileGL::Wire::LogLine *CtrlEnvelope::msg_as() const { + return msg_as_LogLine(); +} + +struct CtrlEnvelopeBuilder { + typedef CtrlEnvelope Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_msg_type(MobileGL::Wire::CtrlMsg msg_type) { + fbb_.AddElement(CtrlEnvelope::VT_MSG_TYPE, static_cast(msg_type), 0); + } + void add_msg(::flatbuffers::Offset msg) { + fbb_.AddOffset(CtrlEnvelope::VT_MSG, msg); + } + explicit CtrlEnvelopeBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateCtrlEnvelope( + ::flatbuffers::FlatBufferBuilder &_fbb, + MobileGL::Wire::CtrlMsg msg_type = MobileGL::Wire::CtrlMsg::NONE, + ::flatbuffers::Offset msg = 0) { + CtrlEnvelopeBuilder builder_(_fbb); + builder_.add_msg(msg); + builder_.add_msg_type(msg_type); + return builder_.Finish(); +} + +struct CtrlEnvelope::Traits { + using type = CtrlEnvelope; + static auto constexpr Create = CreateCtrlEnvelope; +}; + +template +inline bool VerifyCtrlMsg(::flatbuffers::VerifierTemplate &verifier, const void *obj, CtrlMsg type) { + switch (type) { + case CtrlMsg::NONE: { + return true; + } + case CtrlMsg::Hello: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::Welcome: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::CapsSnapshot: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::SurfaceOp: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::SurfaceReply: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::ResyncRequest: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::ResyncDone: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::AuxRequest: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::Fatal: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case CtrlMsg::LogLine: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: return true; + } +} + +template +inline bool VerifyCtrlMsgVector(::flatbuffers::VerifierTemplate &verifier, const ::flatbuffers::Vector<::flatbuffers::Offset> *values, const ::flatbuffers::Vector *types) { + if (!values || !types) return !values && !types; + if (values->size() != types->size()) return false; + for (::flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyCtrlMsg( + verifier, values->Get(i), types->GetEnum(i))) { + return false; + } + } + return true; +} + +inline const MobileGL::Wire::CtrlEnvelope *GetCtrlEnvelope(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const MobileGL::Wire::CtrlEnvelope *GetSizePrefixedCtrlEnvelope(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *CtrlEnvelopeIdentifier() { + return "MGLC"; +} + +inline bool CtrlEnvelopeBufferHasIdentifier(const void *buf) { + return ::flatbuffers::BufferHasIdentifier( + buf, CtrlEnvelopeIdentifier()); +} + +inline bool SizePrefixedCtrlEnvelopeBufferHasIdentifier(const void *buf) { + return ::flatbuffers::BufferHasIdentifier( + buf, CtrlEnvelopeIdentifier(), true); +} + +template +inline bool VerifyCtrlEnvelopeBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifyBuffer(CtrlEnvelopeIdentifier()); +} + +template +inline bool VerifySizePrefixedCtrlEnvelopeBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifySizePrefixedBuffer(CtrlEnvelopeIdentifier()); +} + +inline void FinishCtrlEnvelopeBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root, CtrlEnvelopeIdentifier()); +} + +inline void FinishSizePrefixedCtrlEnvelopeBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root, CtrlEnvelopeIdentifier()); +} + +} // namespace Wire +} // namespace MobileGL + +#endif // FLATBUFFERS_GENERATED_PROTOCOL_MOBILEGL_WIRE_H_ diff --git a/MobileGL/MG_Remote/Protocol/mg_protocol_base.h b/MobileGL/MG_Remote/Protocol/mg_protocol_base.h new file mode 100644 index 00000000..b3555c31 --- /dev/null +++ b/MobileGL/MG_Remote/Protocol/mg_protocol_base.h @@ -0,0 +1,120 @@ +// MobileGL - MobileGL/MG_Remote/Protocol/mg_protocol_base.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +// Shared vocabulary of the MG_Remote wire contracts (transport, framing, ring, +// shm). Inherited from the earlier `Feat/CS-Delta-IPC` branch +// (MobileGL/Protocol/mg_protocol_base.h) and cut down to what plan B's +// transport actually needs: result codes, byte spans, a shm region reference +// and the id typedefs. +// +// Deliberately NOT inherited: MobileGLObjectKind / MobileGLObjectScope / +// MobileGLObjectHandle. Plan B does not put GL object identity on the wire at +// all - the frontend allocates {slot, generation} handles in MG_Pipe +// (PLAN-B.md section 4.2.1) and those are the only identity the backend ever +// sees, so a second object-identity vocabulary here would be a drift surface +// with no reader. +// +// This header must stay: +// - pure C (compilable from C and C++, no MG C++ types, no exceptions/RTTI), +// - dependency-free (only //), +// - append-only within an ABI major (see versioning rules below). +// +// Versioning rules (contract-wide): +// - Every versioned struct starts with uint32_t structSize. +// - Appending fields at the tail is a MINOR bump; receivers must ignore +// bytes beyond the structSize they know. +// - Changing/removing/reordering existing fields is a MAJOR bump. +// - A major mismatch is a hard, structured failure, never an exception. +// (Plan B keeps the structSize-first discipline as the answer to risk B-R10, +// PLAN-B.md section 14.2.) + +#ifndef MOBILEGL_REMOTE_PROTOCOL_BASE_H +#define MOBILEGL_REMOTE_PROTOCOL_BASE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// --------------------------------------------------------------------------- +// ABI versions +// --------------------------------------------------------------------------- + +#define MOBILEGL_PROTOCOL_ABI_MAJOR 1 +#define MOBILEGL_PROTOCOL_ABI_MINOR 0 + +#define MOBILEGL_ABI_VERSION(major, minor) (((uint32_t)(major) << 16) | (uint32_t)(minor)) +#define MOBILEGL_ABI_MAJOR_OF(version) ((uint32_t)(version) >> 16) +#define MOBILEGL_ABI_MINOR_OF(version) ((uint32_t)(version) & 0xFFFFu) + +// --------------------------------------------------------------------------- +// Ids +// --------------------------------------------------------------------------- + +typedef uint64_t MobileGLSessionId; // one client GL context flow +typedef uint64_t MobileGLRequestSeq; // matches a request to its reply +typedef uint32_t MobileGLSegmentId; // shm segment id within a connection + +// --------------------------------------------------------------------------- +// Spans / regions +// --------------------------------------------------------------------------- + +// Borrowed, read-only byte span. The pointee is owned by the producing side +// and is only valid for the duration documented at the consuming call site. +typedef struct MobileGLByteSpan { + const void* data; + uint64_t size; +} MobileGLByteSpan; + +typedef struct MobileGLMutableByteSpan { + void* data; + uint64_t size; +} MobileGLMutableByteSpan; + +// A byte range inside an already-established shm segment. Segments are +// announced out of band (the SegmentRef table on the control channel, with the +// fd itself passed by SCM_RIGHTS) and stay stable for their declared lifetime; +// offsets are segment-relative. +typedef struct MobileGLShmRegion { + MobileGLSegmentId segmentId; + uint32_t reserved; + uint64_t offset; + uint64_t size; +} MobileGLShmRegion; + +// --------------------------------------------------------------------------- +// Result codes (structured errors across every contract boundary) +// --------------------------------------------------------------------------- + +typedef enum MobileGLResult { + MOBILEGL_OK = 0, + MOBILEGL_ERR_NOT_INITIALIZED = 1, + MOBILEGL_ERR_INVALID_ARGUMENT = 2, + MOBILEGL_ERR_UNSUPPORTED = 3, + MOBILEGL_ERR_OUT_OF_MEMORY = 4, + MOBILEGL_ERR_PROTOCOL_MISMATCH = 5, // ABI/wire major mismatch, bad framing + MOBILEGL_ERR_TRANSPORT_CLOSED = 6, // peer gone / EOF + MOBILEGL_ERR_TIMEOUT = 7, // nothing arrived within the deadline + MOBILEGL_ERR_SHM_EXHAUSTED = 8, + MOBILEGL_ERR_SESSION_UNKNOWN = 9, + MOBILEGL_ERR_HANDLE_UNKNOWN = 10, + // The caller's buffer is smaller than the pending message. The message is + // NOT consumed and the required size is reported back; see + // ITransport::ReceiveFrame. + MOBILEGL_ERR_BUFFER_TOO_SMALL = 11, + MOBILEGL_ERR_FORCE_U32 = 0x7FFFFFFF +} MobileGLResult; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // MOBILEGL_REMOTE_PROTOCOL_BASE_H diff --git a/MobileGL/MG_Remote/Protocol/protocol.fbs b/MobileGL/MG_Remote/Protocol/protocol.fbs new file mode 100644 index 00000000..968f235b --- /dev/null +++ b/MobileGL/MG_Remote/Protocol/protocol.fbs @@ -0,0 +1,235 @@ +// MobileGL - MobileGL/MG_Remote/Protocol/protocol.fbs +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +// MobileGL disaggregated wire protocol - CONTROL PLANE ONLY. +// +// Plan B (docs plan "MGPipe") section 8.1 inherits the transport design of the +// earlier plan verbatim, and its section 7.1 splits the schema in two: +// +// - rare / variable-length / must-evolve messages -> FlatBuffers *tables*, +// carried as complete framed messages over the control channel. That is +// everything in this file. +// - the hot path -> FlatBuffers *structs* (fixed layout, no vtable, no +// offset indirection) written straight into the SEG_CMD ring. Those +// records are generated from MG_Pipe/PipeCalls.def and are deliberately +// NOT in this schema yet: the call catalogue is a separate P0 deliverable +// and record numbering must never churn. +// +// Regeneration: scripts/gen_protocol.py (flatc is NOT part of the default +// build graph). generated/protocol_generated.h is committed and CI's +// flatc-check regenerates it and runs `git diff --exit-code`. + +namespace MobileGL.Wire; + +// --------------------------------------------------------------------------- +// Segments +// --------------------------------------------------------------------------- + +// Segment layout is inherited unchanged (earlier plan section 6.1): +// SEG_CMD 8MiB / SEG_STAGE 32MiB+ / SEG_REPLY 8MiB / SEG_EVENT 256KiB / +// SEG_SHADOW[n] / SEG_ADOPT[n]. +enum SegmentKind : ubyte { + None = 0, + Cmd = 1, // client-owned command ring (RingControl + records) + Stage = 2, // client-owned bulk staging + Reply = 3, // server-owned reply pool + Event = 4, // server-owned event ring + Shadow = 5, // client-owned per-object shadow (P4.5+) + Adopt = 6, // server-owned adopted store, client RW (>= 16MiB) +} + +// The fd itself never travels in a message: POSIX passes it with SCM_RIGHTS on +// the aux socket (ITransport::ShareFd), Windows resolves `name`. +table SegmentRef { + id: uint; + kind: SegmentKind; + sizeBytes: ulong; + name: string; +} + +// --------------------------------------------------------------------------- +// Handshake +// --------------------------------------------------------------------------- + +table Hello { + abiMajor: uint; + abiMinor: uint; + buildFingerprint: string; + backendType: uint; + pid: uint; + configBlob: [ubyte]; +} + +table Welcome { + abiMajor: uint; + abiMinor: uint; + serverPid: uint; + cmdRing: SegmentRef; + stageRing: SegmentRef; + replyPool: SegmentRef; + eventRing: SegmentRef; +} + +// --------------------------------------------------------------------------- +// Capabilities +// --------------------------------------------------------------------------- + +// Replaces the 40 `pActiveBackendObject->` reads plus the 89 caps read sites +// (plan B appendix A, `get_caps`). The three blobs are byte-for-byte images of +// the corresponding POD structs; they are versioned by structSize-first +// discipline, not by this schema. +table CapsSnapshot { + dynamicParameters: [ubyte]; + rendererInfo: [ubyte]; + formatCaps: [ubyte]; + extensions: [string]; + apiVersion: string; + maxComputeWorkGroupCount: [int]; // 3 entries + maxComputeWorkGroupSize: [int]; // 3 entries + tableSlotMask: ulong; // which GLFunctionsTable slots the peer registered + prefersCpuXfbPrimitiveAccounting: bool; +} + +table DefaultFramebufferInfo { + width: int; + height: int; + colorFormat: uint; + depthFormat: uint; + stencilFormat: uint; +} + +// --------------------------------------------------------------------------- +// Surface / EGL lifecycle +// --------------------------------------------------------------------------- + +enum SurfaceOpKind : ubyte { + None = 0, + InitializeDisplay = 1, + CreateWindowSurface = 2, + CreatePbufferSurface = 3, + ResizeWindowSurface = 4, + ReleaseSurface = 5, + MakeCurrent = 6, + ReleaseCurrent = 7, +} + +enum WindowKind : ubyte { + None = 0, + AndroidNativeWindow = 1, + X11 = 2, + Win32Hwnd = 3, + Surfaceless = 4, + Pbuffer = 5, +} + +table SurfaceOp { + seq: ulong; + kind: SurfaceOpKind; + display: ulong; + surface: ulong; + windowKind: WindowKind; + nativeToken: ulong; // X11 XID / HWND; Android transfers the window out of band + width: int; + height: int; + swapInterval: int; +} + +table SurfaceReply { + seq: ulong; + ok: bool; + eglMajor: int; + eglMinor: int; + defaultFb: DefaultFramebufferInfo; +} + +// --------------------------------------------------------------------------- +// Resync / aux / diagnostics +// --------------------------------------------------------------------------- + +// Sent by the client after it observes a serverEpoch bump (context lost or +// server restart): every cached ring offset and every server-side object is +// gone and the whole pushed state has to be replayed. +table ResyncRequest { + serverEpoch: uint; +} + +table ResyncDone {} + +enum AuxRequestKind : ubyte { + None = 0, + FenceClientWait = 1, + QueryResult = 2, + ScalarGet = 3, +} + +// Requests issued from a thread that is not the ring producer (foreign-thread +// sync / query polling), so they cannot take the SPSC ring. +table AuxRequest { + seq: ulong; + kind: AuxRequestKind; + payload: [ubyte]; +} + +enum FatalCode : uint { + None = 0, + ProtocolCorruption = 1, // record bounds / self-describing length violated + RingOverrun = 2, + SegmentMismatch = 3, + DeviceLost = 4, + ServerCrashed = 5, + AbiMismatch = 6, +} + +table Fatal { + code: FatalCode; + message: string; +} + +// Severity-graded per plan B section 8.2: <= Warn is lossy, >= Error is +// lossless and rate limited. +enum LogLevel : ubyte { + Debug = 0, + Info = 1, + Warn = 2, + Error = 3, + Fatal = 4, +} + +table LogLine { + level: LogLevel; + text: string; +} + +// --------------------------------------------------------------------------- +// Envelope +// --------------------------------------------------------------------------- + +// Union tags are wire values: only ever APPEND to this list. +// ProgramReflection from the earlier plan's section 7.1 is intentionally +// absent - plan B ships program artifacts inside the create_shader_state CSO +// blob, so if a control-plane reflection message is ever needed it appends +// here rather than reserving a tag today. +union CtrlMsg { + Hello, + Welcome, + CapsSnapshot, + SurfaceOp, + SurfaceReply, + ResyncRequest, + ResyncDone, + AuxRequest, + Fatal, + LogLine, +} + +table CtrlEnvelope { + msg: CtrlMsg; +} + +root_type CtrlEnvelope; +file_identifier "MGLC"; diff --git a/scripts/gen_protocol.py b/scripts/gen_protocol.py new file mode 100644 index 00000000..6420b43a --- /dev/null +++ b/scripts/gen_protocol.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +"""Regenerate MobileGL/MG_Remote/Protocol/generated/protocol_generated.h from protocol.fbs. + +flatc is a developer/CI tool ONLY: it is never part of the default build graph +(the earlier branch's Protocol/CMakeLists.txt:22-38 did add_subdirectory the +FlatBuffers tree and turned FLATBUFFERS_BUILD_FLATC ON when +MOBILEGL_FLATC_EXECUTABLE was unset, which is exactly the NDK trap it claimed +to avoid: cross-compiling an arm64 flatc and then trying to run it on the +host). The FlatBuffers runtime is header-only, so a build only needs +3rdparty/flatbuffers/include on the include path. + +flatc resolution order: + 1. --flatc / MOBILEGL_FLATC_EXECUTABLE + 2. a flatc built once from the pinned 3rdparty/flatbuffers submodule into a + directory OUTSIDE the repository (default: /../flatc-build, + override with MOBILEGL_FLATC_BUILD_DIR) + +A flatc found on PATH is deliberately NOT used: the generated header carries a +FLATBUFFERS_VERSION static_assert against the runtime headers, so a stray flatc +of another version produces a header that either fails to compile or churns the +committed file on every machine. +""" + +from __future__ import annotations + +import argparse +import os +import re +import shutil +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +SCHEMA = REPO_ROOT / "MobileGL" / "MG_Remote" / "Protocol" / "protocol.fbs" +OUT_DIR = REPO_ROOT / "MobileGL" / "MG_Remote" / "Protocol" / "generated" +OUT_FILE = OUT_DIR / "protocol_generated.h" +SUBMODULE = REPO_ROOT / "3rdparty" / "flatbuffers" + +LICENSE_HEADER = """\ +// MobileGL - MobileGL/MG_Remote/Protocol/generated/protocol_generated.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +// GENERATED FILE - DO NOT EDIT. +// Regenerate with `python3 scripts/gen_protocol.py` after changing +// MobileGL/MG_Remote/Protocol/protocol.fbs. CI's flatc-check step regenerates +// this file and fails on `git diff --exit-code`. +""" + + +def submodule_version() -> str | None: + base = SUBMODULE / "include" / "flatbuffers" / "base.h" + if not base.is_file(): + return None + text = base.read_text(encoding="utf-8", errors="replace") + parts = [] + for macro in ("FLATBUFFERS_VERSION_MAJOR", "FLATBUFFERS_VERSION_MINOR", + "FLATBUFFERS_VERSION_REVISION"): + match = re.search(r"#\s*define\s+" + macro + r"\s+(\d+)", text) + if not match: + return None + parts.append(match.group(1)) + return ".".join(parts) + + +def flatc_version(flatc: Path) -> str | None: + try: + out = subprocess.run([str(flatc), "--version"], check=True, + capture_output=True, text=True).stdout + except (OSError, subprocess.CalledProcessError): + return None + match = re.search(r"(\d+\.\d+\.\d+)", out) + return match.group(1) if match else None + + +def build_flatc(build_dir: Path, jobs: int) -> Path: + if not (SUBMODULE / "CMakeLists.txt").is_file(): + sys.exit(f"error: {SUBMODULE} is empty - run " + f"`git submodule update --init 3rdparty/flatbuffers`") + exe_name = "flatc.exe" if os.name == "nt" else "flatc" + for candidate in (build_dir / exe_name, build_dir / "Release" / exe_name): + if candidate.is_file(): + return candidate + + build_dir.mkdir(parents=True, exist_ok=True) + cmake = shutil.which("cmake") + if cmake is None: + sys.exit("error: cmake not found; needed to build flatc from the submodule") + configure = [ + cmake, "-S", str(SUBMODULE), "-B", str(build_dir), + "-DCMAKE_BUILD_TYPE=Release", + "-DFLATBUFFERS_BUILD_FLATC=ON", + "-DFLATBUFFERS_BUILD_FLATLIB=OFF", + "-DFLATBUFFERS_BUILD_FLATHASH=OFF", + "-DFLATBUFFERS_BUILD_TESTS=OFF", + "-DFLATBUFFERS_INSTALL=OFF", + ] + if shutil.which("ninja"): + configure += ["-G", "Ninja"] + print("[gen_protocol] configuring flatc:", " ".join(configure), flush=True) + subprocess.run(configure, check=True) + print("[gen_protocol] building flatc", flush=True) + subprocess.run([cmake, "--build", str(build_dir), "--target", "flatc", + "--config", "Release", "--parallel", str(jobs)], check=True) + + for candidate in (build_dir / exe_name, build_dir / "Release" / exe_name): + if candidate.is_file(): + return candidate + sys.exit(f"error: flatc was not produced under {build_dir}") + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--flatc", default=os.environ.get("MOBILEGL_FLATC_EXECUTABLE", ""), + help="path to a flatc binary (default: $MOBILEGL_FLATC_EXECUTABLE)") + parser.add_argument("--build-dir", + default=os.environ.get("MOBILEGL_FLATC_BUILD_DIR", ""), + help="where to build flatc from the submodule " + "(default: /../flatc-build, kept out of the repo)") + parser.add_argument("--jobs", type=int, default=os.cpu_count() or 4) + parser.add_argument("--check", action="store_true", + help="fail if the committed header is not what flatc produces") + parser.add_argument("--allow-version-mismatch", action="store_true", + help="proceed when flatc's version differs from the submodule's") + args = parser.parse_args() + + if not SCHEMA.is_file(): + sys.exit(f"error: schema not found: {SCHEMA}") + + if args.flatc: + flatc = Path(args.flatc) + if not flatc.is_file(): + sys.exit(f"error: --flatc/{'MOBILEGL_FLATC_EXECUTABLE'} points at a " + f"missing file: {flatc}") + else: + build_dir = Path(args.build_dir) if args.build_dir else REPO_ROOT.parent / "flatc-build" + flatc = build_flatc(build_dir.resolve(), args.jobs) + + have, want = flatc_version(flatc), submodule_version() + print(f"[gen_protocol] flatc={flatc} version={have} submodule={want}", flush=True) + if have and want and have != want and not args.allow_version_mismatch: + sys.exit(f"error: flatc {have} does not match the pinned FlatBuffers runtime " + f"{want}; the generated header's version static_assert would fail. " + f"Unset MOBILEGL_FLATC_EXECUTABLE to build the pinned flatc, or pass " + f"--allow-version-mismatch.") + + OUT_DIR.mkdir(parents=True, exist_ok=True) + previous = OUT_FILE.read_bytes() if OUT_FILE.is_file() else None + + cmd = [str(flatc), "--cpp", "--cpp-std", "c++17", "-o", str(OUT_DIR), str(SCHEMA)] + print("[gen_protocol]", " ".join(cmd), flush=True) + subprocess.run(cmd, check=True, cwd=str(REPO_ROOT)) + + if not OUT_FILE.is_file(): + sys.exit(f"error: flatc did not produce {OUT_FILE}") + + body = OUT_FILE.read_text(encoding="utf-8") + OUT_FILE.write_text(LICENSE_HEADER + "\n" + body, encoding="utf-8", newline="\n") + + if args.check and previous is not None and previous != OUT_FILE.read_bytes(): + sys.exit("error: committed protocol_generated.h is stale; rerun " + "scripts/gen_protocol.py and commit the result") + + print(f"[gen_protocol] wrote {OUT_FILE.relative_to(REPO_ROOT)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())