mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 18:13:23 +09:00
[MG_Remote, MG_Test, scripts] (P12): WindowKind::ServerOwned on the wire - control revision 3 with SurfaceRefusal and SurfaceReply width/height/refusal, the codec's ServerOwned rules (creation only, token 0, SetWindowHandle a named refusal) on a frame-local marker, and the non-zero-token latch row
This commit is contained in:
@@ -56,6 +56,26 @@ namespace MobileGL::MG_Remote {
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceOpKind::SetWindowHandle) == 10 &&
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceOpKind::InitCapabilities) == 11);
|
||||
static_assert(static_cast<Uint8>(::MobileGL::Wire::WindowKind::MetalLayer) == 6);
|
||||
// P12's append, on the same terms: the value is wire ABI.
|
||||
static_assert(static_cast<Uint8>(::MobileGL::Wire::WindowKind::ServerOwned) == 7);
|
||||
// The frame's refusal codes ARE the wire's SurfaceRefusal (SurfaceControlFrame.h), pinned
|
||||
// value by value so a schema edit that renumbers either side fails here.
|
||||
using Server::SurfaceRefusalCode;
|
||||
static_assert(static_cast<Uint8>(SurfaceRefusalCode::None) ==
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::None));
|
||||
static_assert(static_cast<Uint8>(SurfaceRefusalCode::NoServerDisplay) ==
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::NoServerDisplay));
|
||||
static_assert(static_cast<Uint8>(SurfaceRefusalCode::NoServerWindow) ==
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::NoServerWindow));
|
||||
static_assert(static_cast<Uint8>(SurfaceRefusalCode::SurfaceModeMismatch) ==
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::SurfaceModeMismatch));
|
||||
static_assert(static_cast<Uint8>(SurfaceRefusalCode::ServerOwnedOnSetWindowHandle) ==
|
||||
static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::ServerOwnedOnSetWindowHandle));
|
||||
// The frame-local ServerOwned tag names no WindowBackend, by construction (D2: no
|
||||
// BackendObject.h enumerator for it - that header is in the pull build, gate G1).
|
||||
static_assert(Server::kServerOwnedWindowBackend >=
|
||||
static_cast<Int>(MG_Backend::WindowBackend::WindowBackendCount),
|
||||
"kServerOwnedWindowBackend collides with a real WindowBackend");
|
||||
|
||||
bool OpNeedsAWindowBackend(SurfaceControlOp op) {
|
||||
return op == SurfaceControlOp::CreateWindowSurface || op == SurfaceControlOp::SetWindowHandle;
|
||||
@@ -72,6 +92,8 @@ namespace MobileGL::MG_Remote {
|
||||
case SurfaceWireError::UnknownWindowKind: return "UnknownWindowKind";
|
||||
case SurfaceWireError::MetalLayerArrived: return "MetalLayerArrived";
|
||||
case SurfaceWireError::AndroidNativeWindowArrived: return "AndroidNativeWindowArrived";
|
||||
case SurfaceWireError::ServerOwnedTokenNotZero: return "ServerOwnedTokenNotZero";
|
||||
case SurfaceWireError::ServerOwnedOnSetWindowHandle: return "ServerOwnedOnSetWindowHandle";
|
||||
}
|
||||
return "<unknown SurfaceWireError>";
|
||||
}
|
||||
@@ -130,17 +152,28 @@ namespace MobileGL::MG_Remote {
|
||||
: SurfaceWireError::InprocOnlyOpOnTheWire;
|
||||
}
|
||||
::MobileGL::Wire::WindowKind windowKind = ::MobileGL::Wire::WindowKind::None;
|
||||
Uint64 nativeToken = frame.nativeToken;
|
||||
if (frame.kind == SurfaceControlOp::CreatePbufferSurface) {
|
||||
// The op implies the shape; the frame carries no windowBackend for it.
|
||||
windowKind = ::MobileGL::Wire::WindowKind::Pbuffer;
|
||||
} else if (OpNeedsAWindowBackend(frame.kind)) {
|
||||
if (!WireWindowKindForWindowBackend(
|
||||
static_cast<MG_Backend::WindowBackend>(frame.windowBackend), &windowKind)) {
|
||||
if (frame.windowBackend == Server::kServerOwnedWindowBackend) {
|
||||
// P12 (D2): the SERVER's window. Only a creation may ask for it - the server picks
|
||||
// the window, so there is nothing for SetWindowHandle to set - and the token is 0
|
||||
// whatever the frame carried: the client's own window value (it may have none)
|
||||
// never reaches the wire (Rule G/H).
|
||||
if (frame.kind != SurfaceControlOp::CreateWindowSurface) {
|
||||
return SurfaceWireError::ServerOwnedOnSetWindowHandle;
|
||||
}
|
||||
windowKind = ::MobileGL::Wire::WindowKind::ServerOwned;
|
||||
nativeToken = 0;
|
||||
} else if (!WireWindowKindForWindowBackend(
|
||||
static_cast<MG_Backend::WindowBackend>(frame.windowBackend), &windowKind)) {
|
||||
return SurfaceWireError::UnknownWindowKind;
|
||||
}
|
||||
}
|
||||
const auto op = ::MobileGL::Wire::CreateSurfaceOp(
|
||||
*builder, frame.seq, kind, frame.display, frame.surface, windowKind, frame.nativeToken,
|
||||
*builder, frame.seq, kind, frame.display, frame.surface, windowKind, nativeToken,
|
||||
frame.width, frame.height, frame.swapInterval, frame.readSurface, frame.context);
|
||||
const auto envelope = ::MobileGL::Wire::CreateCtrlEnvelope(*builder, ::MobileGL::Wire::CtrlMsg::SurfaceOp, op.Union());
|
||||
::MobileGL::Wire::FinishCtrlEnvelopeBuffer(*builder, envelope);
|
||||
@@ -163,6 +196,23 @@ namespace MobileGL::MG_Remote {
|
||||
decoded.height = op.height();
|
||||
decoded.swapInterval = op.swapInterval();
|
||||
if (OpNeedsAWindowBackend(kind)) {
|
||||
if (op.windowKind() == ::MobileGL::Wire::WindowKind::ServerOwned) {
|
||||
// P12 (D2). Asked BEFORE the Android refusal below, which it is not: the window is
|
||||
// the server's own. A creation only (SetWindowHandle may not name it - a named
|
||||
// refusal, not corruption: nothing about the bytes is malformed), and a token of 0
|
||||
// only (anything else is a value from the peer's window system trying to cross,
|
||||
// Rule G - that one is corruption).
|
||||
if (kind != SurfaceControlOp::CreateWindowSurface) {
|
||||
return SurfaceWireError::ServerOwnedOnSetWindowHandle;
|
||||
}
|
||||
if (op.nativeToken() != 0) {
|
||||
return SurfaceWireError::ServerOwnedTokenNotZero;
|
||||
}
|
||||
decoded.windowBackend = Server::kServerOwnedWindowBackend;
|
||||
decoded.nativeToken = 0;
|
||||
*frame = decoded;
|
||||
return SurfaceWireError::None;
|
||||
}
|
||||
if (op.windowKind() == ::MobileGL::Wire::WindowKind::AndroidNativeWindow) {
|
||||
// The one refusal that is not corruption: the window kind is LEGAL and the token
|
||||
// is an ANativeWindow*, which names memory in the CLIENT's process. Real window
|
||||
@@ -175,8 +225,10 @@ namespace MobileGL::MG_Remote {
|
||||
}
|
||||
MG_Backend::WindowBackend backend;
|
||||
if (!WindowBackendForWireWindowKind(op.windowKind(), &backend)) {
|
||||
// THE UPPER BOUND IS THE LAST APPENDED KIND (P12: ServerOwned), for the reason
|
||||
// SurfaceControlOpForWireKind's bound gives.
|
||||
return ::flatbuffers::IsOutRange(op.windowKind(), ::MobileGL::Wire::WindowKind::None,
|
||||
::MobileGL::Wire::WindowKind::MetalLayer)
|
||||
::MobileGL::Wire::WindowKind::ServerOwned)
|
||||
? SurfaceWireError::UnknownWindowKind
|
||||
: SurfaceWireError::WindowKindNamesNoBackend;
|
||||
}
|
||||
@@ -189,8 +241,10 @@ namespace MobileGL::MG_Remote {
|
||||
|
||||
void EncodeSurfaceReplyFrame(const SurfaceControlFrame& frame,
|
||||
flatbuffers::FlatBufferBuilder* builder) {
|
||||
const auto reply = ::MobileGL::Wire::CreateSurfaceReply(*builder, frame.seq, frame.ok, frame.eglMajor,
|
||||
frame.eglMinor, /*defaultFb=*/0, frame.eventHead);
|
||||
// P12: the reply's surface geometry and refusal (SurfaceReply.width/height/refusal).
|
||||
const auto reply = ::MobileGL::Wire::CreateSurfaceReply(
|
||||
*builder, frame.seq, frame.ok, frame.eglMajor, frame.eglMinor, /*defaultFb=*/0, frame.eventHead,
|
||||
frame.width, frame.height, static_cast<::MobileGL::Wire::SurfaceRefusal>(frame.refusal));
|
||||
const auto envelope =
|
||||
::MobileGL::Wire::CreateCtrlEnvelope(*builder, ::MobileGL::Wire::CtrlMsg::SurfaceReply, reply.Union());
|
||||
::MobileGL::Wire::FinishCtrlEnvelopeBuffer(*builder, envelope);
|
||||
@@ -202,6 +256,9 @@ namespace MobileGL::MG_Remote {
|
||||
frame->eglMajor = reply.eglMajor();
|
||||
frame->eglMinor = reply.eglMinor();
|
||||
frame->eventHead = reply.eventHead();
|
||||
frame->width = reply.width();
|
||||
frame->height = reply.height();
|
||||
frame->refusal = static_cast<Uint8>(reply.refusal());
|
||||
}
|
||||
|
||||
MobileGLResult ServerApplyWireSurfaceOp(const ::MobileGL::Wire::SurfaceOp& op, SurfaceControlFrame* replyOut) {
|
||||
@@ -211,10 +268,39 @@ namespace MobileGL::MG_Remote {
|
||||
if (SessionLatched()) return MOBILEGL_ERR_PROTOCOL_MISMATCH;
|
||||
SurfaceControlFrame frame;
|
||||
const SurfaceWireError error = DecodeWireSurfaceOp(op, &frame);
|
||||
if (error == SurfaceWireError::ServerOwnedOnSetWindowHandle) {
|
||||
// P12 (D2): A NAMED REFUSAL, NOT A LATCH. Nothing in the bytes is malformed - the op
|
||||
// simply asks for something the protocol does not do (the server chooses its own
|
||||
// window at CreateWindowSurface; there is nothing for SetWindowHandle to set). So it
|
||||
// is answered ok=false, by name, and the session goes on, armed or not.
|
||||
MGLOG_E("MG_Remote server: Refuse ServerOwned on SetWindowHandle - a wire SetWindowHandle "
|
||||
"(seq %llu) named WindowKind::ServerOwned. The server-owned window is chosen by the "
|
||||
"server when CreateWindowSurface asks for it; SetWindowHandle may not name it "
|
||||
"(refusal ServerOwnedOnSetWindowHandle, session not latched)",
|
||||
static_cast<unsigned long long>(op.seq()));
|
||||
if (replyOut != nullptr) {
|
||||
*replyOut = SurfaceControlFrame{};
|
||||
replyOut->seq = op.seq();
|
||||
replyOut->ok = false;
|
||||
replyOut->refusal = static_cast<Uint8>(Server::SurfaceRefusalCode::ServerOwnedOnSetWindowHandle);
|
||||
}
|
||||
return MOBILEGL_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (error != SurfaceWireError::None) {
|
||||
// PH-1 (3): the op's bytes are the peer's. Each of the three refusals latches in an
|
||||
// armed session child and the op is answered with no dispatch; unarmed they die.
|
||||
if (error == SurfaceWireError::AndroidNativeWindowArrived) {
|
||||
if (error == SurfaceWireError::ServerOwnedTokenNotZero) {
|
||||
// P12 (D2): WindowKind::ServerOwned names the SERVER's window, so its token is 0 by
|
||||
// definition. A non-zero one is a value from the peer's window system trying to
|
||||
// cross (Rule G) - the peer's corrupt bytes, latched like the rows beside it.
|
||||
(void)SessionLatch(MGFatalFamily::ProtocolCorruption,
|
||||
"MGPipe: Fatal{ProtocolCorruption, \"SurfaceOp.nativeToken\"} - a wire %s named "
|
||||
"WindowKind::ServerOwned with native token 0x%llx. The server-owned window is the "
|
||||
"server's own and its token is always 0: no value from the client's window system "
|
||||
"crosses (Rule G)",
|
||||
::MobileGL::Wire::EnumNameSurfaceOpKind(op.kind()),
|
||||
static_cast<unsigned long long>(op.nativeToken()));
|
||||
} else if (error == SurfaceWireError::AndroidNativeWindowArrived) {
|
||||
(void)SessionLatch(MGFatalFamily::UnmigratedSurface,
|
||||
"MGPipe: Fatal{UnmigratedSurface, \"AndroidNativeWindow@P12\"} - a wire "
|
||||
"SurfaceOp (%s) named an ANativeWindow*, which is a pointer into the "
|
||||
|
||||
@@ -30,6 +30,14 @@
|
||||
// Fatal{ProtocolCorruption, "SurfaceOp"}. P6's control pump is the intended caller; P5f's unit
|
||||
// tests drive it directly. MetalLayerArrived likewise dies
|
||||
// Fatal{UnmigratedSurface, "MetalLayer@P12"}: CAMetalLayer* is also process-local.
|
||||
//
|
||||
// P12 (on-screen server window). WindowKind::ServerOwned is the one window kind whose window is
|
||||
// NOT the client's: the server substitutes its own (ServerLoop.cpp's ServerOwned arm). The codec
|
||||
// maps it onto the frame-local Server::kServerOwnedWindowBackend and writes/reads nativeToken 0,
|
||||
// always - so the client's window value never reaches the wire. A ServerOwned op with a non-zero
|
||||
// token is a peer's corrupt bytes (Fatal{ProtocolCorruption, "SurfaceOp.nativeToken"}, latched);
|
||||
// SetWindowHandle naming it is a named refusal (SurfaceRefusal::ServerOwnedOnSetWindowHandle),
|
||||
// answered and not latched.
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
@@ -56,6 +64,10 @@ namespace MobileGL::MG_Remote {
|
||||
UnknownWindowKind, // a WindowKind the mapping table does not know
|
||||
MetalLayerArrived, // -> Fatal{UnmigratedSurface, "MetalLayer@P12"}
|
||||
AndroidNativeWindowArrived, // -> Fatal{UnmigratedSurface, "AndroidNativeWindow@P12"}
|
||||
// P12 (on-screen server window), D2. WindowKind::ServerOwned is legal on
|
||||
// CreateWindowSurface only, and only with nativeToken 0:
|
||||
ServerOwnedTokenNotZero, // -> Fatal{ProtocolCorruption, "SurfaceOp.nativeToken"}, latched
|
||||
ServerOwnedOnSetWindowHandle, // -> a NAMED REFUSAL (reply ok=false), not a latch
|
||||
};
|
||||
|
||||
const char* SurfaceWireErrorName(SurfaceWireError error);
|
||||
|
||||
@@ -337,11 +337,12 @@ enum class WindowKind : uint8_t {
|
||||
Surfaceless = 4,
|
||||
Pbuffer = 5,
|
||||
MetalLayer = 6,
|
||||
ServerOwned = 7,
|
||||
MIN = None,
|
||||
MAX = MetalLayer
|
||||
MAX = ServerOwned
|
||||
};
|
||||
|
||||
inline const WindowKind (&EnumValuesWindowKind())[7] {
|
||||
inline const WindowKind (&EnumValuesWindowKind())[8] {
|
||||
static const WindowKind values[] = {
|
||||
WindowKind::None,
|
||||
WindowKind::AndroidNativeWindow,
|
||||
@@ -349,13 +350,14 @@ inline const WindowKind (&EnumValuesWindowKind())[7] {
|
||||
WindowKind::Win32Hwnd,
|
||||
WindowKind::Surfaceless,
|
||||
WindowKind::Pbuffer,
|
||||
WindowKind::MetalLayer
|
||||
WindowKind::MetalLayer,
|
||||
WindowKind::ServerOwned
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char * const *EnumNamesWindowKind() {
|
||||
static const char * const names[8] = {
|
||||
static const char * const names[9] = {
|
||||
"None",
|
||||
"AndroidNativeWindow",
|
||||
"X11",
|
||||
@@ -363,17 +365,57 @@ inline const char * const *EnumNamesWindowKind() {
|
||||
"Surfaceless",
|
||||
"Pbuffer",
|
||||
"MetalLayer",
|
||||
"ServerOwned",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameWindowKind(WindowKind e) {
|
||||
if (::flatbuffers::IsOutRange(e, WindowKind::None, WindowKind::MetalLayer)) return "";
|
||||
if (::flatbuffers::IsOutRange(e, WindowKind::None, WindowKind::ServerOwned)) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesWindowKind()[index];
|
||||
}
|
||||
|
||||
enum class SurfaceRefusal : uint8_t {
|
||||
None = 0,
|
||||
NoServerDisplay = 1,
|
||||
NoServerWindow = 2,
|
||||
SurfaceModeMismatch = 3,
|
||||
ServerOwnedOnSetWindowHandle = 4,
|
||||
MIN = None,
|
||||
MAX = ServerOwnedOnSetWindowHandle
|
||||
};
|
||||
|
||||
inline const SurfaceRefusal (&EnumValuesSurfaceRefusal())[5] {
|
||||
static const SurfaceRefusal values[] = {
|
||||
SurfaceRefusal::None,
|
||||
SurfaceRefusal::NoServerDisplay,
|
||||
SurfaceRefusal::NoServerWindow,
|
||||
SurfaceRefusal::SurfaceModeMismatch,
|
||||
SurfaceRefusal::ServerOwnedOnSetWindowHandle
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char * const *EnumNamesSurfaceRefusal() {
|
||||
static const char * const names[6] = {
|
||||
"None",
|
||||
"NoServerDisplay",
|
||||
"NoServerWindow",
|
||||
"SurfaceModeMismatch",
|
||||
"ServerOwnedOnSetWindowHandle",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameSurfaceRefusal(SurfaceRefusal e) {
|
||||
if (::flatbuffers::IsOutRange(e, SurfaceRefusal::None, SurfaceRefusal::ServerOwnedOnSetWindowHandle)) return "";
|
||||
const size_t index = static_cast<size_t>(e);
|
||||
return EnumNamesSurfaceRefusal()[index];
|
||||
}
|
||||
|
||||
enum class AuxRequestKind : uint8_t {
|
||||
None = 0,
|
||||
FenceClientWait = 1,
|
||||
@@ -1820,7 +1862,10 @@ struct SurfaceReply FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
VT_EGLMAJOR = 8,
|
||||
VT_EGLMINOR = 10,
|
||||
VT_DEFAULTFB = 12,
|
||||
VT_EVENTHEAD = 14
|
||||
VT_EVENTHEAD = 14,
|
||||
VT_WIDTH = 16,
|
||||
VT_HEIGHT = 18,
|
||||
VT_REFUSAL = 20
|
||||
};
|
||||
uint64_t seq() const {
|
||||
return GetField<uint64_t>(VT_SEQ, 0);
|
||||
@@ -1840,6 +1885,15 @@ struct SurfaceReply FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
uint64_t eventHead() const {
|
||||
return GetField<uint64_t>(VT_EVENTHEAD, 0);
|
||||
}
|
||||
int32_t width() const {
|
||||
return GetField<int32_t>(VT_WIDTH, 0);
|
||||
}
|
||||
int32_t height() const {
|
||||
return GetField<int32_t>(VT_HEIGHT, 0);
|
||||
}
|
||||
MobileGL::Wire::SurfaceRefusal refusal() const {
|
||||
return static_cast<MobileGL::Wire::SurfaceRefusal>(GetField<uint8_t>(VT_REFUSAL, 0));
|
||||
}
|
||||
template <bool B = false>
|
||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
@@ -1850,6 +1904,9 @@ struct SurfaceReply FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
VerifyOffset(verifier, VT_DEFAULTFB) &&
|
||||
verifier.VerifyTable(defaultFb()) &&
|
||||
VerifyField<uint64_t>(verifier, VT_EVENTHEAD, 8) &&
|
||||
VerifyField<int32_t>(verifier, VT_WIDTH, 4) &&
|
||||
VerifyField<int32_t>(verifier, VT_HEIGHT, 4) &&
|
||||
VerifyField<uint8_t>(verifier, VT_REFUSAL, 1) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -1876,6 +1933,15 @@ struct SurfaceReplyBuilder {
|
||||
void add_eventHead(uint64_t eventHead) {
|
||||
fbb_.AddElement<uint64_t>(SurfaceReply::VT_EVENTHEAD, eventHead, 0);
|
||||
}
|
||||
void add_width(int32_t width) {
|
||||
fbb_.AddElement<int32_t>(SurfaceReply::VT_WIDTH, width, 0);
|
||||
}
|
||||
void add_height(int32_t height) {
|
||||
fbb_.AddElement<int32_t>(SurfaceReply::VT_HEIGHT, height, 0);
|
||||
}
|
||||
void add_refusal(MobileGL::Wire::SurfaceRefusal refusal) {
|
||||
fbb_.AddElement<uint8_t>(SurfaceReply::VT_REFUSAL, static_cast<uint8_t>(refusal), 0);
|
||||
}
|
||||
explicit SurfaceReplyBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
@@ -1894,13 +1960,19 @@ inline ::flatbuffers::Offset<SurfaceReply> CreateSurfaceReply(
|
||||
int32_t eglMajor = 0,
|
||||
int32_t eglMinor = 0,
|
||||
::flatbuffers::Offset<MobileGL::Wire::DefaultFramebufferInfo> defaultFb = 0,
|
||||
uint64_t eventHead = 0) {
|
||||
uint64_t eventHead = 0,
|
||||
int32_t width = 0,
|
||||
int32_t height = 0,
|
||||
MobileGL::Wire::SurfaceRefusal refusal = MobileGL::Wire::SurfaceRefusal::None) {
|
||||
SurfaceReplyBuilder builder_(_fbb);
|
||||
builder_.add_eventHead(eventHead);
|
||||
builder_.add_seq(seq);
|
||||
builder_.add_height(height);
|
||||
builder_.add_width(width);
|
||||
builder_.add_defaultFb(defaultFb);
|
||||
builder_.add_eglMinor(eglMinor);
|
||||
builder_.add_eglMajor(eglMajor);
|
||||
builder_.add_refusal(refusal);
|
||||
builder_.add_ok(ok);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,9 @@ extern "C" {
|
||||
// bump: `python3 scripts/ci/protocol_revision_pin.py --write` records the new row.
|
||||
// 1 P7 wave 2-F, PH-7 (4): Welcome.dataNonce and the DataBind message.
|
||||
// 2 P7 (p7/spawnhang): the SurfaceProgress message.
|
||||
#define MOBILEGL_PROTOCOL_CONTROL_REVISION 2
|
||||
// 3 P12 (on-screen server window): WindowKind.ServerOwned, the SurfaceRefusal enum and
|
||||
// SurfaceReply.width/height/refusal.
|
||||
#define MOBILEGL_PROTOCOL_CONTROL_REVISION 3
|
||||
|
||||
#define MOBILEGL_ABI_VERSION(major, minor) (((uint32_t)(major) << 16) | (uint32_t)(minor))
|
||||
#define MOBILEGL_ABI_MAJOR_OF(version) ((uint32_t)(version) >> 16)
|
||||
|
||||
@@ -247,6 +247,22 @@ enum WindowKind : ubyte {
|
||||
// the two enums may only meet through the explicit mapping table in Protocol/SurfaceOpCodec.cpp
|
||||
// - Surfaceless/Pbuffer are surface SHAPES, not window backends, and answer "no backend" there.
|
||||
MetalLayer = 6,
|
||||
// P12 (on-screen server window), appended. THE WINDOW IS THE SERVER'S OWN: the client asks the
|
||||
// server to create the surface on the window the server process owns (the display Activity's
|
||||
// SurfaceView) and has none of its own to name, so `nativeToken` is always 0 and no pointer
|
||||
// crosses (Rule G/H). Legal on CreateWindowSurface only; SetWindowHandle may not name it.
|
||||
ServerOwned = 7,
|
||||
}
|
||||
|
||||
// P12, appended: WHY A SURFACE OP WAS DECLINED, so the client can name the refusal in its own log
|
||||
// instead of reading a bare `ok = false`. None of these latches the session: each is a
|
||||
// configuration or ordering answer, not a peer's corrupt bytes.
|
||||
enum SurfaceRefusal : ubyte {
|
||||
None = 0,
|
||||
NoServerDisplay = 1, // ServerOwned asked of a server that owns no display
|
||||
NoServerWindow = 2, // the server owns a display, but no window came within its wait
|
||||
SurfaceModeMismatch = 3, // the session's surface mode (on-screen / offscreen) is the other one
|
||||
ServerOwnedOnSetWindowHandle = 4, // SetWindowHandle named the server's own window
|
||||
}
|
||||
|
||||
table SurfaceOp {
|
||||
@@ -255,7 +271,7 @@ table SurfaceOp {
|
||||
display: ulong;
|
||||
surface: ulong;
|
||||
windowKind: WindowKind;
|
||||
nativeToken: ulong; // X11 XID / HWND; Android transfers the window out of band
|
||||
nativeToken: ulong; // X11 XID / HWND; 0 for ServerOwned (the server substitutes its own window)
|
||||
width: int;
|
||||
height: int;
|
||||
swapInterval: int;
|
||||
@@ -275,6 +291,14 @@ table SurfaceReply {
|
||||
defaultFb: DefaultFramebufferInfo;
|
||||
// P6.5: all preceding data-plane events must arrive before this reply is observed.
|
||||
eventHead: ulong;
|
||||
// P12, appended. The surface's REAL extent as the server has it - for a ServerOwned
|
||||
// CreateWindowSurface, the server window's size - so a headless client knows its surface
|
||||
// geometry when eglCreateWindowSurface returns, before any backend has published a
|
||||
// surface-changed event (Magma creates its swapchain only at the first MakeCurrent). 0/0 for
|
||||
// every other op.
|
||||
width: int;
|
||||
height: int;
|
||||
refusal: SurfaceRefusal;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -53,4 +53,15 @@ namespace MobileGL::MG_Remote::Server {
|
||||
}
|
||||
}
|
||||
|
||||
const char* SurfaceRefusalCodeName(SurfaceRefusalCode code) {
|
||||
switch (code) {
|
||||
case SurfaceRefusalCode::None: return "None";
|
||||
case SurfaceRefusalCode::NoServerDisplay: return "NoServerDisplay";
|
||||
case SurfaceRefusalCode::NoServerWindow: return "NoServerWindow";
|
||||
case SurfaceRefusalCode::SurfaceModeMismatch: return "SurfaceModeMismatch";
|
||||
case SurfaceRefusalCode::ServerOwnedOnSetWindowHandle: return "ServerOwnedOnSetWindowHandle";
|
||||
}
|
||||
return "<unknown SurfaceRefusalCode>";
|
||||
}
|
||||
|
||||
} // namespace MobileGL::MG_Remote::Server
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
//
|
||||
// PROCESS-LOCAL WINDOW OBJECTS ARE REFUSED BY NAME on the wire: ANativeWindow* and
|
||||
// CAMetalLayer* mean nothing in the server process. SurfaceOpCodec names their refusals
|
||||
// AndroidNativeWindow@P12 and MetalLayer@P12; real window arrival is P12.
|
||||
// AndroidNativeWindow@P12 and MetalLayer@P12, and they stay (Rule H): P12 does not carry a
|
||||
// client's window across, it gives the SERVER a window of its own (kServerOwnedWindowBackend
|
||||
// below, WindowKind::ServerOwned on the wire).
|
||||
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
@@ -72,6 +74,33 @@ namespace MobileGL::MG_Remote::Server {
|
||||
ProbeForTesting = 14, // MG_Test's arbitrary-work seam through the same channel
|
||||
};
|
||||
|
||||
// P12 (on-screen server window), D2. THE SERVER-OWNED WINDOW, AS A FRAME-LOCAL TAG.
|
||||
//
|
||||
// A client that sets MOBILEGL_IPC_SURFACE=server has no window the server could use (it may
|
||||
// have none at all), so its CreateWindowSurface names the SERVER's window instead: the wire's
|
||||
// WindowKind::ServerOwned with nativeToken 0. Inside a process the request travels in the
|
||||
// frame's `windowBackend` slot as this value - deliberately NOT a MG_Backend::WindowBackend
|
||||
// enumerator (BackendObject.h is in the pull build, gate G1), and deliberately outside every
|
||||
// range a WindowBackend could grow to, so a frame carrying it that ever reached
|
||||
// UnpackWindowHandle would be refused by WindowBackendFromFrameValue's range check rather than
|
||||
// cast. The server's ServerOwned arm (ServerLoop.cpp) consumes it before that point and
|
||||
// substitutes its own window there; no pointer crosses the wire (Rule G/H).
|
||||
inline constexpr Int kServerOwnedWindowBackend = 0x10000;
|
||||
|
||||
// P12. Why the server declined a surface op, carried back in the reply half (`refusal`). The
|
||||
// values ARE the wire's SurfaceRefusal (protocol.fbs); SurfaceOpCodec pins the agreement with
|
||||
// static_asserts, the way it pins SurfaceControlOp against SurfaceOpKind. None of them latches
|
||||
// the session.
|
||||
enum class SurfaceRefusalCode : Uint8 {
|
||||
None = 0,
|
||||
NoServerDisplay = 1, // ServerOwned asked of a server that owns no display
|
||||
NoServerWindow = 2, // a display, but no window within the wait
|
||||
SurfaceModeMismatch = 3, // D4: the session's surface mode is the other one
|
||||
ServerOwnedOnSetWindowHandle = 4, // SetWindowHandle named the server's own window
|
||||
};
|
||||
|
||||
const char* SurfaceRefusalCodeName(SurfaceRefusalCode code);
|
||||
|
||||
struct SurfaceControlFrame {
|
||||
SurfaceControlOp kind = SurfaceControlOp::None;
|
||||
// Minted by the poster (RunSurfaceControlFrame), echoed back with the reply. 0 means
|
||||
@@ -97,6 +126,10 @@ namespace MobileGL::MG_Remote::Server {
|
||||
Int eglMajor = 0;
|
||||
Int eglMinor = 0;
|
||||
Uint64 eventHead = 0; // data-plane delivery fence carried by SurfaceReply
|
||||
// P12: a SurfaceRefusalCode (0 = none). `width`/`height` above double as the reply's
|
||||
// surface geometry: a ServerOwned CreateWindowSurface answers with the server window's
|
||||
// real extent there (SurfaceReply.width/height).
|
||||
Uint8 refusal = 0;
|
||||
};
|
||||
|
||||
namespace Detail {
|
||||
@@ -111,7 +144,8 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// Exhaustive by the language's aggregate decomposition rule: adding ANY member
|
||||
// without extending this binding is a compile error, so new fields cannot evade it.
|
||||
const auto& [kind, seq, display, surface, readSurface, context, windowBackend,
|
||||
nativeToken, width, height, swapInterval, ok, eglMajor, eglMinor, eventHead] = frame;
|
||||
nativeToken, width, height, swapInterval, ok, eglMajor, eglMinor, eventHead,
|
||||
refusal] = frame;
|
||||
return IsSurfaceControlValue<decltype(kind)> && IsSurfaceControlValue<decltype(seq)> &&
|
||||
IsSurfaceControlValue<decltype(display)> && IsSurfaceControlValue<decltype(surface)> &&
|
||||
IsSurfaceControlValue<decltype(readSurface)> && IsSurfaceControlValue<decltype(context)> &&
|
||||
@@ -119,7 +153,7 @@ namespace MobileGL::MG_Remote::Server {
|
||||
IsSurfaceControlValue<decltype(width)> && IsSurfaceControlValue<decltype(height)> &&
|
||||
IsSurfaceControlValue<decltype(swapInterval)> && IsSurfaceControlValue<decltype(ok)> &&
|
||||
IsSurfaceControlValue<decltype(eglMajor)> && IsSurfaceControlValue<decltype(eglMinor)> &&
|
||||
IsSurfaceControlValue<decltype(eventHead)>;
|
||||
IsSurfaceControlValue<decltype(eventHead)> && IsSurfaceControlValue<decltype(refusal)>;
|
||||
}
|
||||
} // namespace Detail
|
||||
|
||||
|
||||
@@ -1262,6 +1262,14 @@ namespace {
|
||||
{"SurfaceOpUnknownKind", "SurfaceOpCodec.cpp", "SurfaceOp", Outcome::Latched,
|
||||
"Fatal{ProtocolCorruption, \"SurfaceOp\"} - a wire surface op failed validation: UnknownOpKind", false,
|
||||
[](Client::ClientSession& c, PeerReport& r) { return SendSurfaceOp(c, r, 200, 0); }},
|
||||
// P12 (D2): WindowKind::ServerOwned names the SERVER's window, so its token is 0 by
|
||||
// definition; SendSurfaceOp's 0x1234 is a client value trying to cross (Rule G).
|
||||
{"SurfaceOpServerOwnedNonZeroToken", "SurfaceOpCodec.cpp", "SurfaceOp.nativeToken", Outcome::Latched,
|
||||
"Fatal{ProtocolCorruption, \"SurfaceOp.nativeToken\"}", false,
|
||||
[](Client::ClientSession& c, PeerReport& r) {
|
||||
return SendSurfaceOp(c, r, kCreateWindowSurface,
|
||||
static_cast<Uint8>(::MobileGL::Wire::WindowKind::ServerOwned));
|
||||
}},
|
||||
// ===== the D11 / PH bounds F2 landed (driver's rows, now with a next session)
|
||||
{"D11CreateRenderStateCsoSlot", "PipeApply.cpp", "CreateRenderState.Cso.Slot", Outcome::Fatal,
|
||||
"Fatal{ProtocolCorruption, \"CreateRenderState.Cso.Slot\"}", false,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"1": "7fc859f7fa756818401f4162e7d49a25d430b91e44d89c297321e3cb36c69638",
|
||||
"2": "b30928e6fc93ddc015fd86f634a6820f775a6f2f6de5a848d273981e706b2597"
|
||||
"2": "b30928e6fc93ddc015fd86f634a6820f775a6f2f6de5a848d273981e706b2597",
|
||||
"3": "da09f0acb48cf245703f28556ef5a38bc9e25241ebbf7b6baa9ab1765b7ddd50"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user