mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
Merge commit '19a4400a' into codex/p5f-wave2
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
#pragma once
|
||||
#include <Includes.h>
|
||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#include <MG_Pipe/MGPipeHandles.h>
|
||||
#endif
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_State::GLState {
|
||||
@@ -33,6 +36,9 @@ namespace MobileGL {
|
||||
struct CopyImageEndpoint {
|
||||
SharedPtr<MG_State::GLState::ITextureObject> Texture;
|
||||
SharedPtr<MG_State::GLState::RenderbufferObject> Renderbuffer;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Pipe::MGPipeHandle TextureHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
|
||||
Bool IsRenderbuffer() const { return Renderbuffer != nullptr; }
|
||||
Bool Exists() const { return Texture != nullptr || Renderbuffer != nullptr; }
|
||||
|
||||
@@ -64,6 +64,14 @@
|
||||
#endif
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// read_pixels writes the server reply scratch; client-side scatter owns any PBO.
|
||||
static const SharedPtr<MG_State::GLState::BufferObject>& SplitReadbackPackBuffer() {
|
||||
static const SharedPtr<MG_State::GLState::BufferObject> none;
|
||||
return none;
|
||||
}
|
||||
#endif
|
||||
|
||||
MG_External::EGLFunctionsTable g_EGLFuncs;
|
||||
MG_External::GLESFunctionsTable g_GLESFuncs;
|
||||
MG_External::GLESCapabilities g_GLESCapabilities;
|
||||
@@ -1520,8 +1528,39 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// gl_NextBuffer is the shape that makes them differ: buffer 0 has stride 0
|
||||
// and nothing bound, so target 0 describes buffer 1.
|
||||
SizeT bufferIndex = 0;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Pipe::MGPipeHandle handle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
struct XfbProgramSource {
|
||||
SharedPtr<MG_State::GLState::ProgramObject> Frontend;
|
||||
SharedPtr<const MG_State::GLState::ProgramArchive> Archive;
|
||||
explicit operator Bool() const { return Frontend || Archive; }
|
||||
const XfbProgramSource* operator->() const { return this; }
|
||||
SizeT GetTransformFeedbackBufferCount() const {
|
||||
return Archive ? Archive->Link.xfbStrides.size() : Frontend->GetTransformFeedbackBufferCount();
|
||||
}
|
||||
Uint32 GetTransformFeedbackStride(Uint32 index) const {
|
||||
return Archive ? (index < Archive->Link.xfbStrides.size() ? Archive->Link.xfbStrides[index] : 0)
|
||||
: Frontend->GetTransformFeedbackStride(index);
|
||||
}
|
||||
Bool NeedsScatteredTransformFeedbackCapture() const {
|
||||
return Archive ? Archive->Link.xfbNeedsScatteredCapture : Frontend->NeedsScatteredTransformFeedbackCapture();
|
||||
}
|
||||
Uint32 GetTransformFeedbackPackedStride() const {
|
||||
return Archive ? Archive->Link.xfbPackedStride : Frontend->GetTransformFeedbackPackedStride();
|
||||
}
|
||||
GLenum GetTransformFeedbackBufferMode() const {
|
||||
return Archive ? Archive->Link.xfbBufferMode : Frontend->GetTransformFeedbackBufferMode();
|
||||
}
|
||||
const auto& GetTransformFeedbackVaryings() const {
|
||||
return Archive ? Archive->Link.xfbVaryings : Frontend->GetTransformFeedbackVaryings();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
// Per frontend transform feedback object. The default object (name 0) maps to
|
||||
// the driver's default object (id 0) and is always present.
|
||||
struct XfbObjectState {
|
||||
@@ -1536,6 +1575,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// End scatters them into `targets`.
|
||||
Bool scattered = false;
|
||||
SharedPtr<MG_State::GLState::ProgramObject> scatterProgram;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
SharedPtr<const MG_State::GLState::ProgramArchive> scatterArchive;
|
||||
#endif
|
||||
SizeT scatterCapacityVertices = 0;
|
||||
};
|
||||
|
||||
@@ -1612,6 +1654,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
if (g_GLESFuncs.glMapBufferRange != nullptr && g_GLESFuncs.glUnmapBuffer != nullptr) {
|
||||
for (const auto& target : targets) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith)
|
||||
#endif
|
||||
if (!target.buffer) continue;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5c: under an active transport the frontend object is client
|
||||
@@ -1619,7 +1664,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// resource's and the captured bytes go back as a writeback EVENT -
|
||||
// WritebackFromBackend from the apply thread is the R1/R2 shape.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const MG_Pipe::MGPipeHandle res = BufferImpl::HandleOfBuffer(target.buffer.get());
|
||||
const MG_Pipe::MGPipeHandle res = target.handle;
|
||||
auto* resource = BufferImpl::FindBufferResourceForHandle(res);
|
||||
if (resource == nullptr || resource->persistentMapped) continue;
|
||||
const SizeT size = target.end - target.start;
|
||||
@@ -1724,7 +1769,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// occupies are written, so the holes gl_SkipComponents asks for keep whatever the
|
||||
// application had put there - which is the whole point of the feature.
|
||||
void ScatterCapturedRecords(XfbObjectState& xfb) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const XfbProgramSource program{xfb.scatterProgram, xfb.scatterArchive};
|
||||
#else
|
||||
const auto& program = xfb.scatterProgram;
|
||||
#endif
|
||||
if (!program || xfb.targets.empty()) return;
|
||||
if (g_GLESFuncs.glMapBufferRange == nullptr || g_GLESFuncs.glUnmapBuffer == nullptr) return;
|
||||
|
||||
@@ -1761,6 +1810,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// whole range down once.
|
||||
for (SizeT targetIndex = 0; targetIndex < xfb.targets.size(); ++targetIndex) {
|
||||
const auto& target = xfb.targets[targetIndex];
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith)
|
||||
#endif
|
||||
if (!target.buffer) continue;
|
||||
// By BUFFER index, not by position in the compacted list - see XfbCaptureTarget.
|
||||
const SizeT stride = program->GetTransformFeedbackStride(static_cast<Uint32>(target.bufferIndex));
|
||||
@@ -1776,7 +1828,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Pipe::MGPipeHandle splitRes = MG_Pipe::kMGPipeNullHandle;
|
||||
BufferImpl::GLESBufferResource* splitResource = nullptr;
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
splitRes = BufferImpl::HandleOfBuffer(target.buffer.get());
|
||||
splitRes = target.handle;
|
||||
splitResource = BufferImpl::FindBufferResourceForHandle(splitRes);
|
||||
const Uint8* hostBytes = splitResource != nullptr ? splitResource->hostBytes : nullptr;
|
||||
if (splitResource == nullptr || hostBytes == nullptr) {
|
||||
@@ -1868,7 +1920,23 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// not captured, and opening the span would also subject it to the capture
|
||||
// primitive-mode rule the paused draw is exempt from.
|
||||
if (!xfb.pending || xfb.paused) return;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
XfbProgramSource program;
|
||||
const MG_Pipe::MGPStreamOutputBegin* span = nullptr;
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const auto& state = MG_Pipe::MGPipeApplier();
|
||||
const auto found = state.StreamOutputSpans.find(state.BoundStreamOutputLifetimeId);
|
||||
if (found != state.StreamOutputSpans.end()) {
|
||||
span = &found->second;
|
||||
const auto* record = PipeShaderCsoRecordForHandle(span->CaptureProgram);
|
||||
if (record) program.Archive = record->Archive;
|
||||
}
|
||||
} else {
|
||||
program.Frontend = MGB_CTX->GetTransformFeedbackProgram();
|
||||
}
|
||||
#else
|
||||
const auto& program = MGB_CTX->GetTransformFeedbackProgram();
|
||||
#endif
|
||||
if (!program) {
|
||||
// The pending flag is deliberately NOT consumed here. It used to be cleared
|
||||
// before this check, so a single draw that could not see the capture program
|
||||
@@ -1888,6 +1956,20 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// recording it here keeps End independent of the frontend capture state.
|
||||
const SizeT bufferCount = program->GetTransformFeedbackBufferCount();
|
||||
for (SizeT i = 0; i < bufferCount; ++i) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (!span || i >= 4) continue;
|
||||
const auto& range = span->Targets[i];
|
||||
if (MG_Pipe::MGPipeHandleIsNull(range.Res) || range.Size == 0) continue;
|
||||
auto* resource = BufferImpl::EnsureBufferResourceForHandle(nullptr, range.Res);
|
||||
if (!resource || resource->id == 0) continue;
|
||||
xfb.targets.push_back({nullptr, resource->id, static_cast<SizeT>(range.Offset),
|
||||
static_cast<SizeT>(range.Offset + range.Size), i, range.Res});
|
||||
BufferImpl::BindBufferRangeCached(GL_TRANSFORM_FEEDBACK_BUFFER, static_cast<GLuint>(i),
|
||||
resource->id, static_cast<GLintptr>(range.Offset), static_cast<GLsizeiptr>(range.Size));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
auto& point = MGB_CTX->GetBufferBindingPoint(BufferTarget::TransformFeedback,
|
||||
static_cast<Uint>(i));
|
||||
const auto& bufferObject = point.GetBoundObject();
|
||||
@@ -1901,12 +1983,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
xfb.targets.push_back({bufferObject, backendResource->id, start, end, i});
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith)
|
||||
#endif
|
||||
BufferImpl::SyncTransformFeedbackBindingPoints(bufferCount);
|
||||
|
||||
// A layout with holes or several interleaved buffers is not expressible on ES:
|
||||
// capture gap-free into scratch storage and place the records at End instead.
|
||||
xfb.scattered = false;
|
||||
xfb.scatterProgram.reset();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
xfb.scatterArchive.reset();
|
||||
#endif
|
||||
xfb.scatterCapacityVertices = 0;
|
||||
if (program->NeedsScatteredTransformFeedbackCapture()) {
|
||||
SizeT capacityVertices = ~SizeT(0);
|
||||
@@ -1922,7 +2010,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (capacityVertices == ~SizeT(0)) capacityVertices = 0;
|
||||
if (BindScatterCaptureBuffer(program->GetTransformFeedbackPackedStride(), capacityVertices)) {
|
||||
xfb.scattered = true;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
xfb.scatterProgram = program.Frontend;
|
||||
xfb.scatterArchive = program.Archive;
|
||||
#else
|
||||
xfb.scatterProgram = program;
|
||||
#endif
|
||||
xfb.scatterCapacityVertices = capacityVertices;
|
||||
} else {
|
||||
// NO SPAN RATHER THAN A SPAN THAT WRITES SOMEWHERE ELSE. The ES program for a
|
||||
@@ -2007,6 +2100,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ScatterCapturedRecords(xfb);
|
||||
xfb.scattered = false;
|
||||
xfb.scatterProgram.reset();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
xfb.scatterArchive.reset();
|
||||
#endif
|
||||
} else {
|
||||
ReadbackCapturedRanges(xfb.targets);
|
||||
}
|
||||
@@ -10757,7 +10853,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
auto unit = MGB_CTX->GetActiveTextureUnit();
|
||||
#if !MOBILEGL_BUILD_DISAGGREGATED
|
||||
auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
|
||||
#endif
|
||||
|
||||
auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||
if (!TextureImpl::IsSupportedTextureTarget(textureTarget)) {
|
||||
@@ -10789,6 +10887,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
|
||||
#endif
|
||||
const auto& bindingSlot = textureUnit.GetBindingSlot(textureTarget);
|
||||
{
|
||||
const auto& textureObject = bindingSlot.GetBoundObject();
|
||||
@@ -12297,8 +12398,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// An endpoint that named nothing is the frontend validator's INVALID_VALUE and never
|
||||
// reaches here - but the assertion that says so is compiled out of a release build, and
|
||||
// SyncTextureObjectToBackend would register a null state object.
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
out.texture = TextureImpl::SyncTextureToBackendByHandle(endpoint.TextureHandle);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!endpoint.Texture) return false;
|
||||
out.texture = TextureImpl::SyncTextureObjectToBackend(endpoint.Texture);
|
||||
}
|
||||
if (!out.texture) return false;
|
||||
const TextureTarget stateTarget = MG_Util::ConvertGLEnumToTextureTarget(appTarget);
|
||||
out.target = TextureImpl::ConvertTextureTargetToBackendGLEnum(stateTarget);
|
||||
@@ -12316,6 +12424,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
static TextureInternalFormat GetCopyImageEndpointFormat(const CopyImageEndpoint& endpoint) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const auto* record = PipeTextureRecordForHandle(endpoint.TextureHandle);
|
||||
return record ? static_cast<TextureInternalFormat>(record->Desc.InternalFormat)
|
||||
: TextureInternalFormat::Unknown;
|
||||
}
|
||||
#endif
|
||||
if (endpoint.IsRenderbuffer()) return endpoint.Renderbuffer->GetInternalFormat();
|
||||
return endpoint.Texture ? endpoint.Texture->GetFormat() : TextureInternalFormat::Unknown;
|
||||
}
|
||||
@@ -12596,6 +12711,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// effect by the block's next use.
|
||||
void ShaderStorageBlockBinding(GLuint program, const GLchar* storageBlockName, GLuint storageBlockBinding) {
|
||||
if (!storageBlockName) return;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const auto handle = MG_Pipe::MGPipeApplier().VerbStorageBlockProgram;
|
||||
auto* slot = PrgramImpl::g_backendProgramObjects.FindByHandle(handle);
|
||||
if (slot && *slot && (*slot)->GetBackendProgramId()) {
|
||||
PrgramImpl::ApplyShaderStorageBlockBinding((*slot)->GetBackendProgramId(),
|
||||
storageBlockName, storageBlockBinding);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!MGB_CTX->ValidateProgramName(program)) return;
|
||||
auto& programObject = MGB_CTX->GetProgramObject(program);
|
||||
if (!programObject) return;
|
||||
@@ -12806,6 +12932,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const SizeT rowBytes = static_cast<SizeT>(width) * dstPixelBytes;
|
||||
const SizeT packedSize = dstOffset + static_cast<SizeT>(height - 1) * dstRowStride + rowBytes;
|
||||
const auto& pixelPackBufferObject =
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
const SizeT pboOffset = reinterpret_cast<SizeT>(pixels);
|
||||
if (pixelPackBufferObject && pboOffset + packedSize > pixelPackBufferObject->GetSize()) {
|
||||
@@ -13788,6 +13919,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return true;
|
||||
}
|
||||
const auto& pixelPackBufferObject =
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
if (!pixelPackBufferObject && pixels == nullptr) {
|
||||
return true;
|
||||
@@ -14025,6 +14161,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Pipe::MGPipeUnmigratedEmulation("get-tex-image-shadow");
|
||||
#endif
|
||||
const auto& pixelPackBufferObject =
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
if (!pixelPackBufferObject && pixels == nullptr) {
|
||||
return true;
|
||||
@@ -14335,6 +14476,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// (the driver-level binding used to stay on the user PBO after this call,
|
||||
// capturing subsequent client-memory readbacks into it).
|
||||
auto& pixelPackBufferObject =
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
Bool usePBO = false;
|
||||
GLuint packBufferId = 0;
|
||||
@@ -14766,6 +14912,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Handle PBO. The pack binding is scoped: it returns to the resting 0 state
|
||||
// on every exit path, so a later readback can never land in a stale PBO.
|
||||
auto& pixelPackBufferObject =
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
Bool usePBO = false;
|
||||
GLuint packBufferId = 0;
|
||||
|
||||
@@ -10287,6 +10287,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// (the three-channel colour-renderable widening). GL answers such a read with 1.0, but
|
||||
// the storage holds whatever the draw wrote there, so the readback has to overwrite it.
|
||||
Bool IsAlphaWidenedFallbackReadAttachment() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const auto* record = MG_Pipe::MGPipeApplier().ReadFramebuffer();
|
||||
return record && IsAlphaWidenedColorSurface(record->ReadSurface);
|
||||
}
|
||||
#endif
|
||||
const auto* attachmentObject = GetReadColorAttachment();
|
||||
if (attachmentObject == nullptr) {
|
||||
return false;
|
||||
@@ -10295,6 +10301,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Bool IsFixedPointFallbackReadAttachment() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
const auto* record = MG_Pipe::MGPipeApplier().ReadFramebuffer();
|
||||
return record && record->ReadSurface.Kind != MG_Pipe::kMGPipeSurfaceKindNone &&
|
||||
IsSnormFormat(static_cast<TextureInternalFormat>(record->ReadSurface.InternalFormat));
|
||||
}
|
||||
#endif
|
||||
const auto& readFBO =
|
||||
MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
|
||||
if (!readFBO) {
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
#include <regex>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// read_pixels writes the server reply scratch; client-side scatter owns any PBO.
|
||||
static const SharedPtr<MG_State::GLState::BufferObject>& SplitReadbackPackBuffer() {
|
||||
static const SharedPtr<MG_State::GLState::BufferObject> none;
|
||||
return none;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const FormatCapabilityCache* ActiveBackendFormatCaps() {
|
||||
// Under a live split session the SERVER's private backend is what owns the context on the
|
||||
@@ -2350,7 +2358,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
static Bool StoreClientRows(SizeT dstPixelBytes, SizeT swapGroupSize, GLsizei width, GLsizei sliceHeight,
|
||||
GLsizei sliceCount, void* pixels, Bool applyPackImageParams, FillRow&& fillRow) {
|
||||
const auto& pixelPackBufferObject =
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
? SplitReadbackPackBuffer() :
|
||||
#endif
|
||||
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
|
||||
// Destination layout is computed from the client-side PACK parameters; only the actual pixel
|
||||
// rows are written so skip regions of the destination stay untouched.
|
||||
|
||||
@@ -2117,6 +2117,18 @@ namespace MobileGL::MG_Pipe {
|
||||
#endif
|
||||
|
||||
SizeT PipeInputs::GetBufferBindingPointCount(BufferTarget target) const {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
switch (target) {
|
||||
case BufferTarget::Uniform:
|
||||
case BufferTarget::ShaderStorage:
|
||||
case BufferTarget::AtomicCounter:
|
||||
case BufferTarget::TransformFeedback:
|
||||
return kMGPipeMaxBufferBindingPoints;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
MGP_STICKY_FORWARD_PULL(GetBufferBindingPointCount);
|
||||
const auto* ctx = LiveContext();
|
||||
return ctx != nullptr ? ctx->GetBufferBindingPointCount(target) : 0;
|
||||
@@ -2135,6 +2147,12 @@ namespace MobileGL::MG_Pipe {
|
||||
}
|
||||
|
||||
Bool PipeInputs::HasOpenTransformFeedbackSpan(Uint64 lifetimeId) const {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
return lifetimeId != 0 && MGPipeApplier().StreamOutputSpans.count(lifetimeId) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
MGP_STICKY_FORWARD_PULL(HasOpenTransformFeedbackSpan);
|
||||
const auto* ctx = LiveContext();
|
||||
return ctx != nullptr && ctx->HasOpenTransformFeedbackSpan(lifetimeId);
|
||||
|
||||
@@ -34,23 +34,10 @@
|
||||
# a row advances those entries to their next one. See docs/Disaggregated/notes/p5f/f1-report.md.
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
#
|
||||
# Espryt's readback path reads the framebuffer binding slot out of the block (the field's
|
||||
# Espryt half retired at P5e for the UNBARRIERED path only; the barriered readback pull is the
|
||||
# residual). The largest block of the census by far.
|
||||
# 132 entries
|
||||
GetFramebufferBindingSlot@ReadPixels
|
||||
# The XFB program check at draw setup (FieldOwnership.def: "P3b/P4b (Espryt), P7 (Magma)").
|
||||
# 11 entries (the TessellationXfbCapture / XfbCaptureBufferReuse family)
|
||||
GetTransformFeedbackProgram@DrawArrays
|
||||
# CopyImageSubData resolves both textures through the sticky forward (def: "P7").
|
||||
# 6 entries
|
||||
GetTextureObject@CopyImageSubData
|
||||
# Magma's Clear path (the two DirectVulkan.Split.NamedBlit entries) - fm's first rows.
|
||||
# 2 entries
|
||||
# P5f fe measured at 881e050e: 181 entries, 175 green, 4 skipped, 2 red.
|
||||
# Espryt retired all five previous first-blocker pairs, and their downstream reads:
|
||||
# READ FBO surface classification + reply-only PixelPack; copy destination arm ordering;
|
||||
# copy-image endpoint handles; capture archive/ranges; storage-block program handle.
|
||||
# The complete lane reached no new first-blocker pair (see fe-report.md).
|
||||
# Magma's Clear path remains fm's independently owned pair (two NamedBlit entries).
|
||||
GetFramebufferBindingSlot@Clear
|
||||
# CopyTexImage2D's texture-unit read (def: "P5e (Espryt unbarriered), P7 (Magma)").
|
||||
# 2 entries
|
||||
GetTextureUnitObject@CopyTexImage2D
|
||||
# The program-name validation sticky forward at ShaderStorageBlockBinding (def: "P9").
|
||||
# 2 entries
|
||||
ValidateProgramName@ShaderStorageBlockBinding
|
||||
|
||||
@@ -19,34 +19,10 @@
|
||||
# <(python3 scripts/gen_pipe_field_ownership.py --print-admitted) this-file
|
||||
# and put the census it prints here.
|
||||
#
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# RE-MEASURED ON THE WAVE-3 INTEGRATION TREE (pa + mv + gl merged), 181 lane entries, 181 green,
|
||||
# ZERO Fatal pairs. The note this block used to carry - that it was measured at gl's base and the
|
||||
# merge would retire three rows - was discharged exactly as written: the ratchet named
|
||||
# GetProgramForDraw@DrawArrays as an expected pair that no longer appears, and named
|
||||
# GetBufferBindingSlot@DrawArrays as one the lane had not seen before. Both are reconciled below.
|
||||
# GetProgramForDispatch@DispatchCompute never reached this file (pa retired it before it was
|
||||
# written) and the ordinary GetBoundVertexArray@DrawArrays is gone; the two that remain under that
|
||||
# name are the client-vertex-array entries, which are escalation-barriered and P8's.
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
#
|
||||
# Admitted by the generated table (disjuncts 1 and 2 of ID-116 / ID-125):
|
||||
GetBufferBindingSlot@ReadPixels
|
||||
# NEW IN WAVE 3, and it was named before it could fire: mv's report called
|
||||
# BoundDrawIndirectBufferId's GetBufferBindingSlot(DrawIndirect) a latent row that "would surface
|
||||
# as GetBufferBindingSlot@DrawArrays if an indirect tier were ever forced under strict", and then
|
||||
# gated the five multi-draw tiers, which forced it. Retires in P8 (FieldOwnership.def:78).
|
||||
GetBufferBindingSlot@DrawArrays
|
||||
GetFramebufferBindingSlot@ReadPixels
|
||||
GetProgramObject@ShaderStorageBlockBinding
|
||||
GetTextureObject@CopyImageSubData
|
||||
GetTextureUnitObject@CopyTexImage2D
|
||||
GetTransformFeedbackProgram@DrawArrays
|
||||
ValidateProgramName@ShaderStorageBlockBinding
|
||||
#
|
||||
# Admitted by ESCALATION only (disjunct 3, ID-128): the record was barriered because its payload
|
||||
# said so - an open transform-feedback span, or a draw carrying client vertex arrays - which no
|
||||
# table indexed by (field, verb) can see. All three are pulls on the draw verb by entries that
|
||||
# are NOT the ordinary draw path.
|
||||
GetBoundVertexArray@DrawArrays
|
||||
GetBufferBindingPoint@DrawArrays
|
||||
# P5f fe census: 179 integration-split entries pass, with zero Fatal, ordinary Admitted,
|
||||
# or ESCALATED pairs. The expected set is therefore empty; either new marker kind is red.
|
||||
# Eight live pairs retired through server framebuffer/texture/program records, reply scratch,
|
||||
# and the Begin XFB snapshot. The two already-stale rows GetBoundVertexArray@DrawArrays and
|
||||
# GetBufferBindingSlot@DrawArrays were independently identified at the f1 baseline (f1-report
|
||||
# section 8.1). fe-report records every removed pair and its source. P8 client-array tests
|
||||
# retain their separate lane; an empty census here does not assert that P8 is implemented.
|
||||
|
||||
@@ -83,11 +83,11 @@
|
||||
/* (:2995) is SELF-DECLARED monolith glue (DirectGLES.cpp:2961-2965) while BindCurrentFBO */ \
|
||||
/* (:4303-4353) is already split-clean - the bind is migrated, the sync is not. */ \
|
||||
X(GetFramebufferBindingSlot, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \
|
||||
"frontend BindingSlot<FramebufferObject> pointer") \
|
||||
"P5f fe: Espryt reads framebuffer records; Magma retains frontend pointer debt") \
|
||||
X(GetImageTextureBinding, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \
|
||||
"frontend ImageTextureBinding base pointer") \
|
||||
X(GetTextureUnitObject, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \
|
||||
"frontend TextureUnit base pointer; 13 Espryt + 8 Magma sites") \
|
||||
"P5f fe: Espryt transport readers retired; Magma retains texture-unit debt") \
|
||||
/* DirectGLES.cpp:4497, PrepareForDraw, the second unconditional pointer read of every draw. */ \
|
||||
X(GetProgramForDraw, BARRIER_PULLED, "P5e (Espryt unbarriered), P7 (Magma)", \
|
||||
"frontend SharedPtr<ProgramObject>; the record carries a handle") \
|
||||
@@ -104,7 +104,7 @@
|
||||
/* case a field census taken from "what the scenario does" rather than from the mask would */ \
|
||||
/* miss. The family's five VALUE rows rode set_context_values out of this list at P5c rv. */ \
|
||||
X(GetTransformFeedbackProgram, BARRIER_PULLED, "P3b/P4b (Espryt), P7 (Magma)", \
|
||||
"frontend SharedPtr<ProgramObject>") \
|
||||
"P5f fe: Espryt capture uses the Begin snapshot; Magma retains program debt") \
|
||||
\
|
||||
/* ---- APPLIER_DERIVED ---- */ \
|
||||
/* THE FIRST ROW, and it is the one the contract asked P5 to split into two field ids. It is */ \
|
||||
@@ -144,14 +144,14 @@
|
||||
/* pair that disagrees. Their poison exemption (generated/PipeFilled.inc:422's sticky arm) */ \
|
||||
/* is cancelled under split by the server stamp, which zeroes their FilledGen - and 0 loses */ \
|
||||
/* to nothing, because :419's "never filled" test runs first. */ \
|
||||
X(GetBufferBindingPointCount, BARRIER_PULLED, "P7/P13", \
|
||||
"an argument-keyed lookup into the frontend's binding-point table") \
|
||||
X(GetBufferBindingPointCount, APPLIER_DERIVED, "-", \
|
||||
"P5f fe: server constant binding-point capacity, no frontend lookup") \
|
||||
X(GetProgramObject, BARRIER_PULLED, "P9", \
|
||||
"hands the backend a frontend SharedPtr<ProgramObject> keyed by GL name") \
|
||||
X(GetTextureObject, BARRIER_PULLED, "P7", \
|
||||
"hands the backend a frontend SharedPtr<ITextureObject> keyed by GL name") \
|
||||
X(HasOpenTransformFeedbackSpan, BARRIER_PULLED, "P7/P9", \
|
||||
"a lookup into frontend XFB span state keyed by lifetime id") \
|
||||
X(HasOpenTransformFeedbackSpan, APPLIER_DERIVED, "-", \
|
||||
"P5f fe: begin/end_stream_output maintain server spans by lifetime id") \
|
||||
X(ValidateProgramName, BARRIER_PULLED, "P9", \
|
||||
"a frontend name-table probe; Coverage.def calls it kClientResolved") \
|
||||
/* P5c ev DELETED the forward under an active transport (CONTRACT-P5C section 4.2): */ \
|
||||
@@ -176,13 +176,13 @@
|
||||
// Mechanism is what replaces the forward, which is NOT the same question as which phase
|
||||
// retires the pull.
|
||||
#define MGP_FIELD_OWNERSHIP_FORWARD_LIST(X) \
|
||||
X(GetBufferBindingPointCount, BARRIER_PULLED, "P7/P13", \
|
||||
X(GetBufferBindingPointCount, APPLIER_DERIVED, "-", \
|
||||
"a server-side binding-point table") \
|
||||
X(GetProgramObject, BARRIER_PULLED, "P9", \
|
||||
"a client-resolved program handle table (ARCHITECTURE 3.2 explicitly-not-ported)") \
|
||||
X(GetTextureObject, BARRIER_PULLED, "P7", \
|
||||
"a server-side texture handle table") \
|
||||
X(HasOpenTransformFeedbackSpan, BARRIER_PULLED, "P7/P9", \
|
||||
X(HasOpenTransformFeedbackSpan, APPLIER_DERIVED, "-", \
|
||||
"server-side XFB span state") \
|
||||
X(ValidateProgramName, BARRIER_PULLED, "P9", \
|
||||
"a client-resolved program name probe") \
|
||||
|
||||
@@ -1669,8 +1669,12 @@ namespace MobileGL::MG_Pipe {
|
||||
struct MGPStreamOutputBegin {
|
||||
Uint32 PrimitiveMode;
|
||||
Uint32 Pad0;
|
||||
// P5f: immutable span snapshot; no frontend pointers survive Begin.
|
||||
MGPipeHandle CaptureProgram;
|
||||
Uint64 LifetimeId;
|
||||
MGPBufferRange Targets[4];
|
||||
};
|
||||
MGP_ASSERT_POD(MGPStreamOutputBegin, 8);
|
||||
MGP_ASSERT_POD(MGPStreamOutputBegin, 120);
|
||||
|
||||
// end_stream_output carries the accounting the client owns; the scatter itself is a
|
||||
// read-modify-write of the client's shadow and lives there (section 7.2.1).
|
||||
|
||||
@@ -1379,6 +1379,12 @@ namespace MobileGL::MG_Pipe {
|
||||
g_applier.DrawProgram = kMGPipeNullHandle;
|
||||
g_applier.DispatchProgram = kMGPipeNullHandle;
|
||||
g_applier.BoundShaderCso = kMGPipeNullHandle;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
g_applier.BoundStreamOutputLifetimeId = 0;
|
||||
// Begin is emitted once per span, not on make-current. Its immutable object
|
||||
// snapshot survives with the resource/program records until End or release;
|
||||
// set_context_values restores the returning context's bound lifetime id.
|
||||
#endif
|
||||
// P5e (sb, CONTRACT-P5E.md §5.6): the three binding-point windows are per-context
|
||||
// WORKING state and go with the rest of it - a returning context has its own
|
||||
// glBindBufferBase history and may not inherit the one this applier was left holding.
|
||||
@@ -1431,6 +1437,10 @@ namespace MobileGL::MG_Pipe {
|
||||
g_applier.DrawProgram = kMGPipeNullHandle;
|
||||
g_applier.DispatchProgram = kMGPipeNullHandle;
|
||||
g_applier.BoundShaderCso = kMGPipeNullHandle;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
g_applier.BoundStreamOutputLifetimeId = 0;
|
||||
g_applier.StreamOutputSpans.clear();
|
||||
#endif
|
||||
// AND "THE WORKING HANDLES THEY COULD NAME" IS ALL OF THEM, NOT JUST THE THREE ABOVE.
|
||||
// Every framebuffer record holds eleven MGPSurface::Res naming texture and renderbuffer
|
||||
// records this function has just dropped - which is why the table itself goes above -
|
||||
@@ -1578,6 +1588,9 @@ namespace MobileGL::MG_Pipe {
|
||||
// memory the rule exists to stop it reading. One store, inert until the caps bit is
|
||||
// published, and it is what makes the two roles' third clause the same clause.
|
||||
g_applier.IsTransformFeedbackActive = values.IsTransformFeedbackActive != 0;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
g_applier.BoundStreamOutputLifetimeId = values.BoundTransformFeedbackLifetimeId;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MGPipeApplySetPatchState(const MGPPatchState& patch) {
|
||||
|
||||
@@ -846,6 +846,9 @@ namespace MobileGL::MG_Pipe {
|
||||
Bool VerbBlitNamedConsumed = false;
|
||||
// copy_framebuffer_to_texture's destination texture (MGPCopyFromFramebuffer::Dst).
|
||||
MGPipeHandle VerbCopyTexDst = kMGPipeNullHandle;
|
||||
MGPipeHandle VerbStorageBlockProgram = kMGPipeNullHandle;
|
||||
Uint64 BoundStreamOutputLifetimeId = 0;
|
||||
UnorderedMap<Uint64, MGPStreamOutputBegin> StreamOutputSpans;
|
||||
// generate_mipmap's texture (MGPMipPlan::Res).
|
||||
MGPipeHandle VerbMipRes = kMGPipeNullHandle;
|
||||
// The current indirect draw's command buffer and (for the *Count forms) parameter
|
||||
@@ -870,6 +873,7 @@ namespace MobileGL::MG_Pipe {
|
||||
VerbBlitDrawFbo = kMGPipeNullHandle;
|
||||
VerbBlitNamedConsumed = false;
|
||||
VerbCopyTexDst = kMGPipeNullHandle;
|
||||
VerbStorageBlockProgram = kMGPipeNullHandle;
|
||||
VerbMipRes = kMGPipeNullHandle;
|
||||
VerbIndirectBuffer = kMGPipeNullHandle;
|
||||
VerbIndirectParameterBuffer = kMGPipeNullHandle;
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
F(Bits) F(ByRegion)
|
||||
|
||||
#define MGP_FIELDS_MGPStreamOutputBegin(F) \
|
||||
F(PrimitiveMode)
|
||||
F(PrimitiveMode) F(CaptureProgram) F(LifetimeId) F(Targets)
|
||||
|
||||
#define MGP_FIELDS_MGPXfbAccounting(F) \
|
||||
F(CapturedVertices) F(PrimitivesWritten) F(PrimitiveMode)
|
||||
|
||||
@@ -42,7 +42,7 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetBoundVertexArray
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingSlot
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPoint
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount
|
||||
MGPipeFieldOwnership::kApplierDerived, // GetBufferBindingPointCount
|
||||
MGPipeFieldOwnership::kRecordSupplied, // GetTouchedBufferBindingPointCount
|
||||
MGPipeFieldOwnership::kRecordSupplied, // GetClampReadColor
|
||||
MGPipeFieldOwnership::kRecordSupplied, // GetClearColor
|
||||
@@ -96,7 +96,7 @@ inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnership[kMGPipeInputFieldCou
|
||||
MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName
|
||||
MGPipeFieldOwnership::kBarrierPulled, // RecordError
|
||||
MGPipeFieldOwnership::kRecordSupplied, // GetBoundTransformFeedbackLifetimeId
|
||||
MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan
|
||||
MGPipeFieldOwnership::kApplierDerived, // HasOpenTransformFeedbackSpan
|
||||
};
|
||||
|
||||
// The ROADMAP phase whose row retires the pull. "-" for every class but BARRIER-PULLED.
|
||||
@@ -109,7 +109,7 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] =
|
||||
"P5e (Espryt unbarriered), P7 (Magma)", // GetBoundVertexArray
|
||||
"P8 (indirect), P9 (readback), P13 (transfer)", // GetBufferBindingSlot
|
||||
"P5e (Espryt unbarriered), P7 (Magma)", // GetBufferBindingPoint
|
||||
"P7/P13", // GetBufferBindingPointCount
|
||||
"-", // GetBufferBindingPointCount
|
||||
"-", // GetTouchedBufferBindingPointCount
|
||||
"-", // GetClampReadColor
|
||||
"-", // GetClearColor
|
||||
@@ -163,7 +163,7 @@ inline constexpr const char* kMGPipeFieldRetiringPhase[kMGPipeInputFieldCount] =
|
||||
"P9", // ValidateProgramName
|
||||
"P9", // RecordError
|
||||
"-", // GetBoundTransformFeedbackLifetimeId
|
||||
"P7/P9", // HasOpenTransformFeedbackSpan
|
||||
"-", // HasOpenTransformFeedbackSpan
|
||||
};
|
||||
|
||||
// The seven sticky forwards, which are among the 63 above and need a row of their own:
|
||||
@@ -182,19 +182,19 @@ inline constexpr MGPipeInputField kMGPipeFieldOwnershipForwardField[kMGPipeField
|
||||
MGPipeInputField::RecordError,
|
||||
};
|
||||
inline constexpr MGPipeFieldOwnership kMGPipeFieldOwnershipForward[kMGPipeFieldOwnershipForwardCount] = {
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetBufferBindingPointCount
|
||||
MGPipeFieldOwnership::kApplierDerived, // GetBufferBindingPointCount
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetProgramObject
|
||||
MGPipeFieldOwnership::kBarrierPulled, // GetTextureObject
|
||||
MGPipeFieldOwnership::kBarrierPulled, // HasOpenTransformFeedbackSpan
|
||||
MGPipeFieldOwnership::kApplierDerived, // HasOpenTransformFeedbackSpan
|
||||
MGPipeFieldOwnership::kBarrierPulled, // ValidateProgramName
|
||||
MGPipeFieldOwnership::kFatal, // InvalidateCompileEnv
|
||||
MGPipeFieldOwnership::kBarrierPulled, // RecordError
|
||||
};
|
||||
inline constexpr const char* kMGPipeFieldOwnershipForwardMechanism[kMGPipeFieldOwnershipForwardCount] = {
|
||||
"a server-side binding-point table", // GetBufferBindingPointCount, retires in P7/P13
|
||||
"a server-side binding-point table", // GetBufferBindingPointCount, retires in -
|
||||
"a client-resolved program handle table (ARCHITECTURE 3.2 explicitly-not-ported)", // GetProgramObject, retires in P9
|
||||
"a server-side texture handle table", // GetTextureObject, retires in P7
|
||||
"server-side XFB span state", // HasOpenTransformFeedbackSpan, retires in P7/P9
|
||||
"server-side XFB span state", // HasOpenTransformFeedbackSpan, retires in -
|
||||
"a client-resolved program name probe", // ValidateProgramName, retires in P9
|
||||
"DELETED under split by P5c ev; the re-arriving caps snapshot IS the invalidation (R-12)", // InvalidateCompileEnv, retires in -
|
||||
"OnGlError, the ordered reverse-channel error post (R-12); its ordering is P9's", // RecordError, retires in P9
|
||||
@@ -323,7 +323,7 @@ inline constexpr SizeT kMGPipeVerbBoundaryExemptCount = 3;
|
||||
// wait. A verb with no stamp row admits nothing - the server stamps only MGP_VERB_OP_LIST's
|
||||
// ops, so no other verb can be the one a residual pull is reported against.
|
||||
inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = {
|
||||
{{0x5808402000000140ull, 0x0000000000000000ull}}, // DrawArrays
|
||||
{{0x1808402000000040ull, 0x0000000000000000ull}}, // DrawArrays
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElements
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElementsBaseVertex
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // MultiDrawArrays
|
||||
@@ -343,7 +343,7 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = {
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawArraysInstanced
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawElementsIndirect
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DrawArraysIndirect
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // Clear
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // Clear
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferfi
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferfv
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearBufferuiv
|
||||
@@ -352,27 +352,27 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = {
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferfi
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferiv
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // ClearNamedFramebufferuiv
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // BlitFramebuffer
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // BlitFramebuffer
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // BlitNamedFramebuffer
|
||||
{{0x5800c02000300180ull, 0x0000000000000000ull}}, // CopyTexImage2D
|
||||
{{0x1800c02000300080ull, 0x0000000000000000ull}}, // CopyTexImage2D
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // CopyTexSubImage2D
|
||||
{{0x5800c02000300180ull, 0x0000000000000000ull}}, // CopyImageSubData
|
||||
{{0x5800c02000300180ull, 0x0000000000000000ull}}, // GenerateMipmap
|
||||
{{0x5800c02000300140ull, 0x0000000000000000ull}}, // ReadPixels
|
||||
{{0x1800c02000300080ull, 0x0000000000000000ull}}, // CopyImageSubData
|
||||
{{0x1800c02000300080ull, 0x0000000000000000ull}}, // GenerateMipmap
|
||||
{{0x1800c02000300040ull, 0x0000000000000000ull}}, // ReadPixels
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // GetTexImage
|
||||
{{0x5800c02000300140ull, 0x0000000000000000ull}}, // GetTextureImage
|
||||
{{0x5800402000000140ull, 0x0000000000000000ull}}, // DispatchCompute
|
||||
{{0x1800c02000300040ull, 0x0000000000000000ull}}, // GetTextureImage
|
||||
{{0x1800402000000040ull, 0x0000000000000000ull}}, // DispatchCompute
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DispatchComputeIndirect
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // MemoryBarrier
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // MemoryBarrier
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // MemoryBarrierByRegion
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // BindImageTexture
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // BindImageTexture
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // GetIntegeri_v
|
||||
{{0x5800c02000300100ull, 0x0000000000000000ull}}, // ShaderStorageBlockBinding
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // FenceSync
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // ClientWaitSync
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // WaitSync
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // DeleteSync
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // GetSyncStatus
|
||||
{{0x1800c02000300000ull, 0x0000000000000000ull}}, // ShaderStorageBlockBinding
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // FenceSync
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // ClientWaitSync
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // WaitSync
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // DeleteSync
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // GetSyncStatus
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // IsTimerQuerySupported
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // BeginTimeElapsedQuery
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // EndTimeElapsedQuery
|
||||
@@ -384,17 +384,17 @@ inline constexpr MGPipeFieldMask kMGPipeAdmittedPullMask[kMGPipeVerbCount] = {
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // EndOcclusionQuery
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // BeginXfbPrimitivesQuery
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // EndXfbPrimitivesQuery
|
||||
{{0x5800402000000100ull, 0x0000000000000000ull}}, // PatchParameteri
|
||||
{{0x5808402000000180ull, 0x0000000000000000ull}}, // BeginTransformFeedback
|
||||
{{0x5808402000000180ull, 0x0000000000000000ull}}, // EndTransformFeedback
|
||||
{{0x5808402000000180ull, 0x0000000000000000ull}}, // PauseTransformFeedback
|
||||
{{0x5808402000000180ull, 0x0000000000000000ull}}, // ResumeTransformFeedback
|
||||
{{0x5808402000000180ull, 0x0000000000000000ull}}, // BindTransformFeedback
|
||||
{{0x1800402000000000ull, 0x0000000000000000ull}}, // PatchParameteri
|
||||
{{0x1808402000000080ull, 0x0000000000000000ull}}, // BeginTransformFeedback
|
||||
{{0x1808402000000080ull, 0x0000000000000000ull}}, // EndTransformFeedback
|
||||
{{0x1808402000000080ull, 0x0000000000000000ull}}, // PauseTransformFeedback
|
||||
{{0x1808402000000080ull, 0x0000000000000000ull}}, // ResumeTransformFeedback
|
||||
{{0x1808402000000080ull, 0x0000000000000000ull}}, // BindTransformFeedback
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // DeleteTransformFeedback
|
||||
{{0x0000000000000000ull, 0x0000000000000000ull}}, // GetGpuTimestampNs
|
||||
};
|
||||
|
||||
inline constexpr SizeT kMGPipeAdmittedPullPairCount = 174;
|
||||
inline constexpr SizeT kMGPipeAdmittedPullPairCount = 128;
|
||||
|
||||
// THE PREDICATE THE STRICT KNOB ASKS (ID-117). A 69 x 128-bit table, so this costs a shift and
|
||||
// a test on the apply thread - the same shape MGPipeFieldMaskHas already has.
|
||||
@@ -428,7 +428,7 @@ static_assert(MGPipeEveryAdmittedPullIsADebtOfItsVerbsClass(),
|
||||
|
||||
// The class sizes, as constants a test can pin without recounting the table.
|
||||
inline constexpr SizeT kMGPipeRecordSuppliedFieldCount = 41;
|
||||
inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 4;
|
||||
inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 15;
|
||||
inline constexpr SizeT kMGPipeApplierDerivedFieldCount = 6;
|
||||
inline constexpr SizeT kMGPipeBarrierPulledFieldCount = 13;
|
||||
inline constexpr SizeT kMGPipeFatalFieldCount = 3;
|
||||
static_assert(kMGPipeRecordSuppliedFieldCount + kMGPipeApplierDerivedFieldCount + kMGPipeBarrierPulledFieldCount + kMGPipeFatalFieldCount == kMGPipeInputFieldCount, "the four class sizes do not partition the field set");
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <MG_Impl/Pipe/FramebufferEmit.h>
|
||||
#include <MG_Impl/Pipe/PipeFill.h>
|
||||
#include <MG_Impl/Pipe/TextureEmit.h>
|
||||
#include <MG_Impl/Pipe/ProgramEmit.h>
|
||||
#include <MG_Pipe/PipeMutation.h>
|
||||
|
||||
namespace MobileGL::MG_Remote::Client {
|
||||
@@ -1412,6 +1413,24 @@ namespace MobileGL::MG_Remote::Client {
|
||||
// The GL token verbatim (contract table 0's "GL enums on the wire"): the sink hands
|
||||
// it to the backend slot that takes it, and nothing between here and there reads it.
|
||||
record.PrimitiveMode = static_cast<Uint32>(primitiveMode);
|
||||
auto& context = *MG_State::pGLContext;
|
||||
record.LifetimeId = context.GetBoundTransformFeedbackLifetimeId();
|
||||
const auto& program = context.GetTransformFeedbackProgram();
|
||||
if (program) {
|
||||
Uint64 bytes = 0;
|
||||
record.CaptureProgram = MG_Pipe::MGPipeProgramEmitterInstance().AcquireShaderCso(*program, bytes);
|
||||
}
|
||||
static_assert(MG_State::GLState::GLContext::MAX_TRANSFORM_FEEDBACK_BUFFERS == 4);
|
||||
for (Uint i = 0; i < 4; ++i) {
|
||||
const auto& point = context.GetBufferBindingPoint(BufferTarget::TransformFeedback, i);
|
||||
const auto& buffer = point.GetBoundObject();
|
||||
if (!buffer) continue;
|
||||
const auto range = point.GetRange();
|
||||
const SizeT start = std::min(range.start, buffer->GetSize());
|
||||
const SizeT end = std::min(range.end, buffer->GetSize());
|
||||
record.Targets[i] = {MG_Pipe::MGPipeResourceTrackerInstance().Find(*buffer), start,
|
||||
end > start ? end - start : 0};
|
||||
}
|
||||
session.EmitAndWait(MG_Pipe::MGPWireOp::BeginStreamOutput, &record, sizeof(record),
|
||||
nullptr, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
@@ -855,9 +855,9 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// retires them by making the backend take the handles that travel beside the names.
|
||||
MG_Backend::CopyImageEndpoint src{};
|
||||
MG_Backend::CopyImageEndpoint dst{};
|
||||
src.Texture = MG_Pipe::gPipeInputs.GetTextureObject(static_cast<Uint>(copy.SrcGlName));
|
||||
dst.Texture = MG_Pipe::gPipeInputs.GetTextureObject(static_cast<Uint>(copy.DstGlName));
|
||||
if (!src.Exists() || !dst.Exists()) {
|
||||
src.TextureHandle = copy.Src;
|
||||
dst.TextureHandle = copy.Dst;
|
||||
if (MG_Pipe::MGPipeHandleIsNull(copy.Src) || MG_Pipe::MGPipeHandleIsNull(copy.Dst)) {
|
||||
// The monolith's own answer to this, in its own words (DirectGLES.cpp:9067
|
||||
// "source or destination image failed to sync; declining the copy"): the frontend
|
||||
// validator is what keeps it unreachable and what reports the INVALID_VALUE the
|
||||
@@ -921,6 +921,8 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// Both backends resolve the PROGRAM through the barrier-pulled GetProgramObject(GlName)
|
||||
// / TryGetDirectVulkanProgram - `rsp` again, retired by P9. ShaderCso travels beside the
|
||||
// name for the phase that dispatches on it.
|
||||
MG_Pipe::MGPipeApplier().ClearVerbHandles();
|
||||
MG_Pipe::MGPipeApplier().VerbStorageBlockProgram = binding.ShaderCso;
|
||||
table->GL.ShaderStorageBlockBinding(static_cast<GLuint>(binding.GlName), name,
|
||||
static_cast<GLuint>(binding.Binding));
|
||||
++m_storageBlockBindings;
|
||||
@@ -944,6 +946,9 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// crash or as a silent success. Contract §2 t2 says so for PatchParameteri by name.
|
||||
|
||||
Bool ServerVerbSink::OnBeginStreamOutput(const MG_Pipe::MGPStreamOutputBegin& begin) {
|
||||
auto& state = MG_Pipe::MGPipeApplier();
|
||||
state.BoundStreamOutputLifetimeId = begin.LifetimeId;
|
||||
state.StreamOutputSpans[begin.LifetimeId] = begin;
|
||||
const MG_Backend::GlobalBackendFunctionsTable* table = Table("begin_stream_output");
|
||||
if (table == nullptr) return false;
|
||||
if (table->GL.BeginTransformFeedback == nullptr) return false;
|
||||
@@ -961,7 +966,11 @@ namespace MobileGL::MG_Remote::Server {
|
||||
Bool ServerVerbSink::OnEndStreamOutput(const MG_Pipe::MGPXfbAccounting& accounting) {
|
||||
const MG_Backend::GlobalBackendFunctionsTable* table = Table("end_stream_output");
|
||||
if (table == nullptr) return false;
|
||||
if (table->GL.EndTransformFeedback == nullptr) return false;
|
||||
if (table->GL.EndTransformFeedback == nullptr) {
|
||||
auto& state = MG_Pipe::MGPipeApplier();
|
||||
state.StreamOutputSpans.erase(state.BoundStreamOutputLifetimeId);
|
||||
return false;
|
||||
}
|
||||
// THE THREE ACCOUNTING FIELDS ARE NOT READ, AND THAT IS THE RULING RATHER THAN AN
|
||||
// OMISSION. glEndTransformFeedback takes no arguments; the numbers are the CLIENT's own
|
||||
// per-span accounting (contract §2 t2's companions row) and the client is where they are
|
||||
@@ -972,6 +981,8 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// server-side scatter is what will need them.
|
||||
(void)accounting;
|
||||
table->GL.EndTransformFeedback();
|
||||
auto& state = MG_Pipe::MGPipeApplier();
|
||||
state.StreamOutputSpans.erase(state.BoundStreamOutputLifetimeId);
|
||||
++m_streamOutputSpans;
|
||||
return true;
|
||||
}
|
||||
@@ -1008,6 +1019,7 @@ namespace MobileGL::MG_Remote::Server {
|
||||
// lifetime of its own - it has no reader on this side today, and pretending otherwise
|
||||
// by folding it into the key is exactly the "a GL name is never an identity" confusion
|
||||
// the contract's GlName row is written against.
|
||||
MG_Pipe::MGPipeApplier().BoundStreamOutputLifetimeId = bind.LifetimeId;
|
||||
table->GL.BindTransformFeedback(static_cast<GLuint>(bind.GlName));
|
||||
++m_streamOutputBinds;
|
||||
return true;
|
||||
|
||||
@@ -263,10 +263,8 @@ TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) {
|
||||
// (CONTRACT-P5C.md §7 table 2) - and the only other BARRIER-PULLED rows are six of the
|
||||
// seven sticky forwards (the seventh, InvalidateCompileEnv, is FATAL since P5c ev).
|
||||
const MGPipeInputField pulledSticky[] = {
|
||||
MGPipeInputField::GetBufferBindingPointCount,
|
||||
MGPipeInputField::GetProgramObject,
|
||||
MGPipeInputField::GetTextureObject,
|
||||
MGPipeInputField::HasOpenTransformFeedbackSpan,
|
||||
MGPipeInputField::ValidateProgramName,
|
||||
MGPipeInputField::RecordError,
|
||||
};
|
||||
@@ -281,7 +279,7 @@ TEST_F(FieldOwnershipTest, TheReducedPathsUnmigratedFieldsAreAllAccountedFor) {
|
||||
EXPECT_TRUE(named) << kMGPipeInputFieldNames[i]
|
||||
<< " is BARRIER-PULLED and not in the pinned object-class list";
|
||||
}
|
||||
EXPECT_EQ(pulledCount, 15u) << "9 non-sticky object rows + 6 sticky forwards";
|
||||
EXPECT_EQ(pulledCount, 13u) << "9 non-sticky object rows + 4 sticky forwards";
|
||||
EXPECT_EQ(pulledCount, kMGPipeBarrierPulledFieldCount);
|
||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetPixelStoreParameters),
|
||||
MGPipeFieldOwnership::kApplierDerived);
|
||||
@@ -705,8 +703,11 @@ TEST_F(FieldOwnershipTest, TheStickyExemptionIsCancelledByTheServerStamp) {
|
||||
MGPipeServerStampVerbBoundary(MGPipeVerb::Clear);
|
||||
for (SizeT i = 0; i < kMGPipeFieldOwnershipForwardCount; ++i) {
|
||||
const MGPipeInputField field = kMGPipeFieldOwnershipForwardField[i];
|
||||
EXPECT_FALSE(MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), field))
|
||||
<< kMGPipeInputFieldNames[Index(field)] << " is still exempt under split";
|
||||
// P5f fe retired the scalar forwards to server-owned answers. Their freshness
|
||||
// comes from that ownership; the remaining client forwards lose the exemption.
|
||||
const Bool serverOwned = MGPipeFieldOwnershipOf(field) == MGPipeFieldOwnership::kApplierDerived;
|
||||
EXPECT_EQ(MGPipeInputFieldIsFresh(gPipeInputs.FilledState(), field), serverOwned)
|
||||
<< kMGPipeInputFieldNames[Index(field)] << " has the wrong server-stamp freshness";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,6 +900,75 @@ namespace {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(FieldOwnershipTest, SplitBindingPointCapacityNeverConsultsTheFrontend) {
|
||||
RoleSplitArm guard;
|
||||
guard.Arm(true);
|
||||
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||
EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::Uniform), 84u);
|
||||
EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::TransformFeedback), 84u);
|
||||
EXPECT_EQ(gPipeInputs.GetBufferBindingPointCount(BufferTarget::PixelPack), 0u);
|
||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::GetBufferBindingPointCount),
|
||||
MGPipeFieldOwnership::kApplierDerived);
|
||||
MGPipeServerClearVerbBoundary();
|
||||
}
|
||||
|
||||
TEST_F(FieldOwnershipTest, SplitOpenSpansAreOwnedByTheApplierAndSurviveOtherBindings) {
|
||||
RoleSplitArm guard;
|
||||
guard.Arm(true);
|
||||
auto& state = MGPipeApplier();
|
||||
state.StreamOutputSpans.clear();
|
||||
MGPipeServerStampVerbBoundary(MGPipeVerb::DrawArrays);
|
||||
EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(0));
|
||||
EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(11));
|
||||
state.StreamOutputSpans[11] = {};
|
||||
state.StreamOutputSpans[12] = {};
|
||||
state.BoundStreamOutputLifetimeId = 12;
|
||||
EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(11));
|
||||
EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(12));
|
||||
state.StreamOutputSpans.erase(12);
|
||||
EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(11));
|
||||
EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(12));
|
||||
EXPECT_EQ(MGPipeFieldOwnershipOf(MGPipeInputField::HasOpenTransformFeedbackSpan),
|
||||
MGPipeFieldOwnership::kApplierDerived);
|
||||
state.StreamOutputSpans.clear();
|
||||
state.BoundStreamOutputLifetimeId = 0;
|
||||
MGPipeServerClearVerbBoundary();
|
||||
}
|
||||
|
||||
TEST_F(FieldOwnershipTest, SplitCaptureSnapshotSurvivesMakeCurrentUntilObjectRelease) {
|
||||
RoleSplitArm guard;
|
||||
guard.Arm(true);
|
||||
auto& state = MGPipeApplier();
|
||||
state.StreamOutputSpans.clear();
|
||||
MGPStreamOutputBegin begin{};
|
||||
begin.LifetimeId = 0x100000002ull;
|
||||
begin.CaptureProgram = {7, 2};
|
||||
begin.Targets[3] = {{9, 3}, 16, 64};
|
||||
state.StreamOutputSpans[begin.LifetimeId] = begin;
|
||||
state.BoundStreamOutputLifetimeId = begin.LifetimeId;
|
||||
|
||||
// Make-current resets binding state, not a live object's open capture. The
|
||||
// returning context emits context values again, but never repeats Begin.
|
||||
MGPipeApplierReset();
|
||||
MGPContextValues returning{};
|
||||
returning.BoundTransformFeedbackLifetimeId = begin.LifetimeId;
|
||||
returning.IsTransformFeedbackActive = 1;
|
||||
MGPipeApplySetContextValues(returning);
|
||||
EXPECT_EQ(state.BoundStreamOutputLifetimeId, begin.LifetimeId);
|
||||
EXPECT_TRUE(gPipeInputs.HasOpenTransformFeedbackSpan(begin.LifetimeId));
|
||||
const auto found = state.StreamOutputSpans.find(begin.LifetimeId);
|
||||
EXPECT_NE(found, state.StreamOutputSpans.end());
|
||||
if (found != state.StreamOutputSpans.end()) {
|
||||
EXPECT_EQ(found->second.CaptureProgram, begin.CaptureProgram);
|
||||
EXPECT_EQ(found->second.Targets[3].Res, begin.Targets[3].Res);
|
||||
EXPECT_EQ(found->second.Targets[3].Offset, 16u);
|
||||
EXPECT_EQ(found->second.Targets[3].Size, 64u);
|
||||
}
|
||||
MGPipeApplierReleaseObjectRecords();
|
||||
EXPECT_FALSE(gPipeInputs.HasOpenTransformFeedbackSpan(begin.LifetimeId));
|
||||
EXPECT_EQ(state.BoundStreamOutputLifetimeId, 0u);
|
||||
}
|
||||
|
||||
TEST_F(FieldOwnershipTest, RoleSplitOffFoldsTheFillSideOntoTheSharedBlock) {
|
||||
EXPECT_FALSE(MGPipeRoleSplitActive());
|
||||
EXPECT_EQ(&MGPipeClientInputs(), &gPipeInputs);
|
||||
|
||||
@@ -1194,6 +1194,9 @@ TEST_F(PipeWireCodecTest, TheFourStreamOutputSpanRowsReachTheSink) {
|
||||
Wire2 wire;
|
||||
MGPStreamOutputBegin begin{};
|
||||
begin.PrimitiveMode = 4;
|
||||
begin.CaptureProgram = MakeHandle(95);
|
||||
begin.LifetimeId = 0x100000002ull;
|
||||
begin.Targets[3] = {MakeHandle(96), 0x100000010ull, 64};
|
||||
MGPStreamOutputControl control{};
|
||||
MGPXfbAccounting end{};
|
||||
end.CapturedVertices = 300;
|
||||
@@ -1210,6 +1213,11 @@ TEST_F(PipeWireCodecTest, TheFourStreamOutputSpanRowsReachTheSink) {
|
||||
}
|
||||
ASSERT_EQ(wire.Sink().Begins.size(), 1u);
|
||||
EXPECT_EQ(wire.Sink().Begins[0].PrimitiveMode, 4u);
|
||||
EXPECT_EQ(wire.Sink().Begins[0].CaptureProgram, MakeHandle(95));
|
||||
EXPECT_EQ(wire.Sink().Begins[0].LifetimeId, 0x100000002ull);
|
||||
EXPECT_EQ(wire.Sink().Begins[0].Targets[3].Res, MakeHandle(96));
|
||||
EXPECT_EQ(wire.Sink().Begins[0].Targets[3].Offset, 0x100000010ull);
|
||||
EXPECT_EQ(wire.Sink().Begins[0].Targets[3].Size, 64u);
|
||||
EXPECT_EQ(wire.Sink().Pauses, 1u);
|
||||
EXPECT_EQ(wire.Sink().Resumes, 1u);
|
||||
ASSERT_EQ(wire.Sink().Ends.size(), 1u);
|
||||
|
||||
Reference in New Issue
Block a user