mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Feat] (P13 W4): Magma monolith takes the record arm in one flip, with in-process persistent-map donation
This commit is contained in:
@@ -465,10 +465,10 @@ namespace MobileGL::MG_ConfigLoader {
|
||||
String lowered = value;
|
||||
std::transform(lowered.begin(), lowered.end(), lowered.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
// P13 W4: the backends switch one at a time. Espryt's record arm runs in monolith from W4a;
|
||||
// Magma's verb entry points pick one arm for every family at once, so it joins at its
|
||||
// single flip, after Espryt's last family.
|
||||
const Bool backendReady = MG_Config::ActiveBackendType == BackendType::DirectGLES;
|
||||
// P13 W4: both backends' monolith runs the record arm - Espryt's from W4a, family by family;
|
||||
// Magma's at its single flip (its verb entry points pick one arm for every family at once).
|
||||
const Bool backendReady = MG_Config::ActiveBackendType == BackendType::DirectGLES ||
|
||||
MG_Config::ActiveBackendType == BackendType::DirectVulkan;
|
||||
MG_Config::MonolithTakesRecordArm = backendReady;
|
||||
if (lowered.empty() || lowered == "record") return;
|
||||
if (lowered == "frontend") {
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
void RejectWireLegacyBuffer() {
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
MGLOG_F("MGPipe: Fatal{RoleViolation, \"buffer-legacy-arm\"} (Magma P7 buffer consumer)");
|
||||
std::abort();
|
||||
}
|
||||
@@ -647,7 +647,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, type, indirect, drawcount, stride, true);
|
||||
return;
|
||||
}
|
||||
@@ -658,7 +658,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, 0, indirect, drawcount, stride, false);
|
||||
return;
|
||||
}
|
||||
@@ -715,7 +715,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
||||
GLsizei maxdrawcount, GLsizei stride) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, type, indirect, maxdrawcount, stride, true, true, drawcount);
|
||||
return;
|
||||
}
|
||||
@@ -727,7 +727,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
||||
GLsizei maxdrawcount, GLsizei stride) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, 0, indirect, maxdrawcount, stride, false, true, drawcount);
|
||||
return;
|
||||
}
|
||||
@@ -805,7 +805,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, type, indirect, 1, 0, true);
|
||||
return;
|
||||
}
|
||||
@@ -870,7 +870,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
void DrawArraysIndirect(GLenum mode, const void* indirect) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
DrawWireIndirect(mode, 0, indirect, 1, 0, false);
|
||||
return;
|
||||
}
|
||||
@@ -948,7 +948,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// DispatchComputeIndirect takes its transport branch into DispatchWireComputeIndirect
|
||||
// (WireDraw.inc), which issues vkCmdDispatchIndirect from the verb's store. The CPU read
|
||||
// that was here (ReadWireBuffer, a whole-GPU wait once a shader had written the store) is gone.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
pVulkanRenderer->DispatchComputeIndirect(indirect);
|
||||
return;
|
||||
}
|
||||
@@ -1015,7 +1015,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
void ShaderStorageBlockBinding(GLuint program, const GLchar* storageBlockName, GLuint storageBlockBinding) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
auto& state = MG_Pipe::MGPipeApplier();
|
||||
const auto handle = state.VerbStorageBlockProgram;
|
||||
if (handle.Slot >= state.ShaderCsos.size() || !state.ShaderCsos[handle.Slot].Live ||
|
||||
@@ -1141,7 +1141,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static Bool BuildClosedLineLoopIndices(GLsizei count, GLenum type, const void* indices,
|
||||
Vector<Uint32>& outIndices) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const SizeT width = MG_Util::GetGLTypeSize(type);
|
||||
if ((width != 1 && width != 2 && width != 4) || count < 2) return false;
|
||||
const auto& bound = MG_Pipe::MGPipeApplier().IndexBuffer;
|
||||
@@ -1249,7 +1249,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// batch that command buffer belongs to - the handle SetupDraw is holding goes stale, and
|
||||
// the next vkCmd* records into a command buffer that is no longer the frame's. Reconciling
|
||||
// HERE, before SetupDraw starts recording, keeps the wait out of the recording.
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) {
|
||||
if (!MG_Config::DataArmIsRecord()) {
|
||||
const auto& currentVAO = MG_Pipe::gPipeInputs.GetBoundVertexArray();
|
||||
Bool clientArray = false;
|
||||
if (currentVAO) {
|
||||
@@ -1319,7 +1319,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// offset is a hardcoded 0, so UploadAndBindIndexBuffer saw a null client pointer,
|
||||
// declined the whole batch and painted nothing.)
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const Bool noIndexBuffer = MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
const Bool noIndexBuffer = MG_Config::DataArmIsRecord()
|
||||
? MG_Pipe::MGPipeHandleIsNull(MG_Pipe::MGPipeApplier().IndexBuffer.Res)
|
||||
: MG_Pipe::gPipeInputs.GetBoundVertexArray()->GetIndexBufferBindingSlot().GetBoundObject() == nullptr;
|
||||
if (noIndexBuffer) {
|
||||
@@ -1451,6 +1451,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// old renderer's GPU work is long complete, and the index must
|
||||
// not be compared against the new renderer's restarted counter.
|
||||
Uint64 rendererGeneration = 0;
|
||||
// P13 W4: status polls answered "not yet" while the batch was still unsubmitted.
|
||||
mutable Uint32 unsubmittedPolls = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -1509,7 +1511,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
// Pure status read (glGetSynciv must not flush).
|
||||
return pVulkanRenderer->IsSubmitIndexComplete(sync->submitIndex);
|
||||
if (pVulkanRenderer->IsSubmitIndexComplete(sync->submitIndex)) return true;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P13 W4: A STATUS POLL THAT CAN NEVER BE ANSWERED. On the record arm a frame's draws stay
|
||||
// in one command buffer (and one render pass) until something submits it, so a client that
|
||||
// only polls - glGetSynciv in a loop, no flush bit, no swap - waits for work nothing will
|
||||
// ever hand the GPU. Under split the apply thread submits when it goes idle (the server's
|
||||
// fence report, one ClientWaitSync(FLUSH, 0)); monolith has no idle moment, so a poller that
|
||||
// keeps asking the same unsubmitted fence is that moment. The threshold keeps an ordinary
|
||||
// once-a-frame status read from splitting the frame it is polled in.
|
||||
constexpr Uint32 kPollsBeforeIdleFlush = 64;
|
||||
if (MG_Config::RecordArmAliasesFrontend() && ++sync->unsubmittedPolls >= kPollsBeforeIdleFlush) {
|
||||
sync->unsubmittedPolls = 0;
|
||||
pVulkanRenderer->FlushForSyncPoint(sync->submitIndex);
|
||||
return pVulkanRenderer->IsSubmitIndexComplete(sync->submitIndex);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// Split staging may also be the destination of a GPU UBO range copy.
|
||||
// Persistent host writes must be coherent: Upload deliberately writes
|
||||
// the mapped pointer without a per-range VMA flush.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith && m_desc.persistentlyMapped) {
|
||||
if (MG_Config::DataArmIsRecord() && m_desc.persistentlyMapped) {
|
||||
bufferDesc.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// A layout transition writes the image too. Order it after the wire
|
||||
// render pass's storeOp, clears and copies instead of relying on the old
|
||||
// per-draw queue-idle path. This applies even when contents are discarded.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith)
|
||||
if (MG_Config::DataArmIsRecord())
|
||||
presentBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
|
||||
#endif
|
||||
presentBarrier.dstAccessMask = 0;
|
||||
@@ -244,7 +244,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
presentBarrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(commandBuffer,
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
MG_Config::DataArmIsRecord()
|
||||
? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
#else
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
|
||||
@@ -591,7 +591,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_programFactory = programFactory;
|
||||
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
vkGetPhysicalDeviceProperties(m_physicalDevice, &properties);
|
||||
m_wireStorageOffsetAlignment = std::max<VkDeviceSize>(1, properties.limits.minStorageBufferOffsetAlignment);
|
||||
|
||||
@@ -802,7 +802,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const auto found = m_wireVertexFormatSupport.find(format);
|
||||
if (found != m_wireVertexFormatSupport.end()) return found->second;
|
||||
VkFormatProperties properties{};
|
||||
|
||||
@@ -216,8 +216,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
},
|
||||
.Destroy = [](auto res) { if (auto* m = WireManager("destroy")) m->DestroyWireBuffer(res); },
|
||||
// Split mapping remains T2: the client owns its map and pushes exact
|
||||
// modified ranges. A server pointer is never donated across the wire.
|
||||
.MapPersistent = [](MG_Pipe::MGPipeHandle, Uint64, const void*) -> void* { return nullptr; },
|
||||
// modified ranges. A server pointer is never donated across the wire. Monolith's record
|
||||
// arm (P13 W4) is one process: there the store IS handed over, as the legacy arm's
|
||||
// AcquirePersistentMap always did.
|
||||
.MapPersistent = [](MG_Pipe::MGPipeHandle res, Uint64 size, const void* seed) -> void* {
|
||||
if (!MG_Config::RecordArmAliasesFrontend()) return nullptr;
|
||||
auto* m = WireManager("map_persistent");
|
||||
return m != nullptr ? m->DonateWireBuffer(res, size, seed) : nullptr;
|
||||
},
|
||||
.UnmapPersistent = [](MG_Pipe::MGPipeHandle) {},
|
||||
#if defined(__ANDROID__)
|
||||
// P11 B2 (T0): the one door a server pointer is still never donated through stays shut;
|
||||
@@ -236,7 +242,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
void VkBufferManager::RegisterWireResourceOps() {
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
MG_Pipe::MGPipeSetResourceOps(&g_vulkanWireResourceOps);
|
||||
}
|
||||
}
|
||||
@@ -771,6 +777,29 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
// P13 W4: THE IN-PROCESS DONATION. Every wire store is already host-visible, coherent and
|
||||
// persistently mapped (RespecifyWireBuffer), so in one process the client can write straight
|
||||
// into it, exactly as the legacy arm's persistent maps did. The store is then the client's
|
||||
// pages - T0's shape without an AHardwareBuffer - so it takes T0's flag: a readback is "done, no
|
||||
// bytes" (the client reads its own pointer once this side's GPU is through with it) and a
|
||||
// respecify retires the store behind the serial. It is seeded from the client's shadow, after
|
||||
// any GPU use of the store has drained, because the shadow is what the application sees.
|
||||
void* VkBufferManager::DonateWireBuffer(MG_Pipe::MGPipeHandle res, Uint64 size, const void* seedBytes) {
|
||||
auto* resource = FindWireBuffer(res);
|
||||
if (resource == nullptr || size == 0 || size != resource->size) return nullptr;
|
||||
void* mapped = resource->buffer.GetMappedData();
|
||||
if (mapped == nullptr) return nullptr;
|
||||
if (resource->imported) return mapped; // already donated: the same pointer
|
||||
if (!WaitForWireBufferHostAccess(*resource)) return nullptr;
|
||||
if (seedBytes != nullptr) std::memcpy(mapped, seedBytes, static_cast<SizeT>(size));
|
||||
resource->imported = true;
|
||||
resource->gpuWritesPending = false;
|
||||
resource->stagedCoverage.clear();
|
||||
MG_Remote::Server::StagedShadowStore::CoverageAdd(resource->stagedCoverage, 0, static_cast<SizeT>(size));
|
||||
++m_sliceEpochCounter;
|
||||
return mapped;
|
||||
}
|
||||
|
||||
Bool VkBufferManager::ImportWireBuffer(MG_Pipe::MGPipeHandle res, void* ahb, Uint64 size) {
|
||||
#if defined(__ANDROID__)
|
||||
auto* resource = FindWireBuffer(res);
|
||||
@@ -1371,7 +1400,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
(MG_Config::Transport != MG_Config::TransportMode::Monolith ? VkBufferUsageFlags{VK_BUFFER_USAGE_TRANSFER_DST_BIT} : 0u) |
|
||||
(MG_Config::DataArmIsRecord() ? VkBufferUsageFlags{VK_BUFFER_USAGE_TRANSFER_DST_BIT} : 0u) |
|
||||
#endif
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
.memoryUsage = m_initInfo.transientMemoryUsage,
|
||||
|
||||
@@ -153,6 +153,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// applies unchanged. The T2 store it replaces goes through DeferWireRelease. False = not
|
||||
// imported (the T2 store is untouched and the client is DECLINED).
|
||||
Bool ImportWireBuffer(MG_Pipe::MGPipeHandle res, void* ahb, Uint64 size);
|
||||
// P13 W4: monolith's record arm donates the wire store itself as the client's persistent
|
||||
// map (see the definition). Null when the store cannot be handed over.
|
||||
void* DonateWireBuffer(MG_Pipe::MGPipeHandle res, Uint64 size, const void* seedBytes);
|
||||
// The POST self-test of the sustained-lock pattern on this device (see the definition).
|
||||
static Bool SelfTestWireImport(char* why, Uint64 whyBytes);
|
||||
#endif
|
||||
|
||||
@@ -2487,9 +2487,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
auto& store = MG_Remote::Server::ServerStagedTexture();
|
||||
// This arm is only ever entered under an active transport, where the store copies.
|
||||
MOBILEGL_ASSERT(store.CopiesIntoServerStorage(),
|
||||
"UploadPendingWireLevels under a non-copying staged store: the wire arm is transport-only");
|
||||
// This arm runs under a transport (the store copies) or on monolith's record arm (it
|
||||
// aliases the frontend's level shadows); a store that holds neither has nothing to upload.
|
||||
MOBILEGL_ASSERT(store.Holds(),
|
||||
"UploadPendingWireLevels under a staged store that holds no levels: the wire arm needs one");
|
||||
const Uint64 key = MG_Remote::Server::StagedTextureStore::KeyForHandle(handle);
|
||||
const TextureInternalFormat internalFormat = static_cast<TextureInternalFormat>(record.Desc.InternalFormat);
|
||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(internalFormat);
|
||||
|
||||
@@ -3220,7 +3220,7 @@ void main() {
|
||||
inline ProgramFactory::CompileOptionFlags GetShaderTransformFlags(VkSurfaceTransformFlagBitsKHR preTransform) {
|
||||
ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionBit::PositionZRemap;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const Bool wire = MG_Config::Transport != MG_Config::TransportMode::Monolith;
|
||||
const Bool wire = MG_Config::DataArmIsRecord();
|
||||
const auto* wireFbo = wire ? MG_Pipe::MGPipeApplier().DrawFramebuffer() : nullptr;
|
||||
const auto currentDrawFBO = wire ? SharedPtr<MG_State::GLState::FramebufferObject>{} :
|
||||
MG_Pipe::gPipeInputs.GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
@@ -5632,7 +5632,7 @@ void main() {
|
||||
// image is a packed depth-stencil texture attached through only one half.
|
||||
{
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const auto* fbo = MG_Pipe::MGPipeApplier().DrawFramebuffer();
|
||||
if (fbo && !fbo->IsDefault) {
|
||||
if (fbo->Depth.Kind == MG_Pipe::kMGPipeSurfaceKindNone) depthTestEnabled = false;
|
||||
@@ -5866,7 +5866,7 @@ void main() {
|
||||
"GetOrCreatePipeline: colorAttachmentCount=%u exceeds payload capacity",
|
||||
payload.colorAttachmentCount);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const auto* wireFbo = MG_Config::Transport != MG_Config::TransportMode::Monolith ?
|
||||
const auto* wireFbo = MG_Config::DataArmIsRecord() ?
|
||||
MG_Pipe::MGPipeApplier().DrawFramebuffer() : nullptr;
|
||||
const auto drawFboBinding = wireFbo ? SharedPtr<MG_State::GLState::FramebufferObject>{} :
|
||||
MG_Pipe::gPipeInputs.GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
@@ -6551,7 +6551,7 @@ void main() {
|
||||
MOBILEGL_ASSERT(
|
||||
[&] {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const auto* fbo = MG_Pipe::MGPipeApplier().DrawFramebuffer();
|
||||
return isDefaultFbo == (fbo != nullptr && fbo->IsDefault);
|
||||
}
|
||||
@@ -6984,7 +6984,7 @@ void main() {
|
||||
// the same loading frame grows it the same way there.
|
||||
SplitOversizedRecording();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
if (!RewindWireDescriptorSetsIfDue()) return false;
|
||||
// The wire route returns before the monolith branch's draw-gated
|
||||
// sweep. Dead wire texture/renderbuffer records otherwise live
|
||||
@@ -7619,7 +7619,7 @@ void main() {
|
||||
// Before the wire branch, for SetupDraw's reason.
|
||||
SplitOversizedRecording();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
if (!RewindWireDescriptorSetsIfDue()) return;
|
||||
m_textureManager->CollectGarbage();
|
||||
DispatchWireCompute(numGroupsX, numGroupsY, numGroupsZ);
|
||||
@@ -7685,7 +7685,7 @@ void main() {
|
||||
SplitOversizedRecording();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P8-SV: the wire arm's own indirect dispatch, DispatchCompute's shape one call over.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
if (!RewindWireDescriptorSetsIfDue()) return;
|
||||
m_textureManager->CollectGarbage();
|
||||
DispatchWireComputeIndirect(indirect);
|
||||
@@ -7797,7 +7797,7 @@ void main() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// ALL_COMMANDS does not include HOST. The barrier's
|
||||
// HOST_WRITE access must have a matching source stage.
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
MG_Config::DataArmIsRecord()
|
||||
? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_HOST_BIT
|
||||
: VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||
#else
|
||||
@@ -7963,7 +7963,7 @@ void main() {
|
||||
|
||||
void VulkanRenderer::Clear(GLbitfield mask) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const auto* fbo = MG_Pipe::MGPipeApplier().DrawFramebuffer();
|
||||
if (!fbo) MagmaWireFatal("clear-framebuffer-record");
|
||||
ClearAttachmentPayload payload{};
|
||||
@@ -8367,7 +8367,7 @@ void main() {
|
||||
void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer,
|
||||
const ClearAttachmentPayload& clearPayload) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const auto* fbo = MG_Pipe::MGPipeApplier().DrawFramebuffer();
|
||||
if (!fbo) MagmaWireFatal("clear-buffer-framebuffer-record");
|
||||
ClearWireFramebuffer(*fbo,clearPayload,buffer == GL_COLOR ? drawbuffer : -1);
|
||||
@@ -9506,7 +9506,7 @@ void main() {
|
||||
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
||||
GLbitfield mask, GLenum filter) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
BlitWireFramebuffers(srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter);
|
||||
return;
|
||||
}
|
||||
@@ -10148,7 +10148,7 @@ void main() {
|
||||
void VulkanRenderer::CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
CopyWireFramebufferToTexture(target,level,xoffset,yoffset,x,y,width,height);
|
||||
return;
|
||||
}
|
||||
@@ -10467,7 +10467,7 @@ void main() {
|
||||
|
||||
Uint CopyImageEndpointName(const CopyImageEndpoint& endpoint) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith)
|
||||
if (MG_Config::DataArmIsRecord())
|
||||
return endpoint.IsRenderbuffer() ? endpoint.RenderbufferHandle.Slot : endpoint.TextureHandle.Slot;
|
||||
#endif
|
||||
if (endpoint.IsRenderbuffer()) return endpoint.Renderbuffer->GetExternalIndex();
|
||||
@@ -10481,7 +10481,7 @@ void main() {
|
||||
GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ,
|
||||
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
const Bool wire = MG_Config::Transport != MG_Config::TransportMode::Monolith;
|
||||
const Bool wire = MG_Config::DataArmIsRecord();
|
||||
MG_Pipe::MGPipeHandle dstStorageHandle = dstEndpoint.TextureHandle;
|
||||
if (wire && HasPendingRecordedWork() && !FlushPendingCommands()) {
|
||||
if (LatchWireDeviceLoss("copy-image-flush")) return;
|
||||
@@ -10529,7 +10529,7 @@ void main() {
|
||||
// render-pass manager, which is where a renderbuffer's VkImage lives.
|
||||
const auto resolveImage = [this](const CopyImageEndpoint& endpoint, CopyImageVkImage& out) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
const Bool renderbuffer = endpoint.IsRenderbuffer();
|
||||
// The same handle-keyed allocation used by wire FBO clear/draw/read.
|
||||
// The legacy render-pass manager owns a different, frontend-keyed map.
|
||||
@@ -10787,7 +10787,7 @@ void main() {
|
||||
|
||||
const auto materializeClear = [this, &frame](const CopyImageEndpoint& endpoint) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) return true;
|
||||
if (MG_Config::DataArmIsRecord()) return true;
|
||||
#endif
|
||||
if (endpoint.IsRenderbuffer()) {
|
||||
return MaterializePendingClearForRenderbuffer(frame.commandBuffer, endpoint.Renderbuffer);
|
||||
@@ -11067,7 +11067,7 @@ void main() {
|
||||
void VulkanRenderer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||
void* pixels) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
ReadWirePixels(x,y,width,height,format,type,pixels);
|
||||
return;
|
||||
}
|
||||
@@ -11769,7 +11769,7 @@ void main() {
|
||||
#endif
|
||||
const auto& pixelPackBufferObject =
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith ? wireReplyHasNoPackBuffer :
|
||||
MG_Config::DataArmIsRecord() ? wireReplyHasNoPackBuffer :
|
||||
#endif
|
||||
MG_Pipe::gPipeInputs.GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
|
||||
const auto packParams = MG_Pipe::gPipeInputs.GetPixelStoreParameters(false);
|
||||
@@ -12047,7 +12047,7 @@ void main() {
|
||||
|
||||
void VulkanRenderer::GenerateMipmap(GLenum target) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
GenerateWireMipmap();
|
||||
return;
|
||||
}
|
||||
@@ -12156,7 +12156,7 @@ void main() {
|
||||
// server's staged shadow (keyed by the synced TextureResource above) and the client's
|
||||
// level storage is never written; in monolith the client-object path runs unchanged.
|
||||
const Bool allocatedMipmapStorage =
|
||||
MG_Config::Transport != MG_Config::TransportMode::Monolith
|
||||
MG_Config::DataArmIsRecord()
|
||||
? EnsureGenerateMipmapShadowAllocated(*resource, baseMipLevel, uploadTargets)
|
||||
: EnsureGenerateMipmapStorageAllocated(*mipmapTexture, baseMipLevel, endMipLevel);
|
||||
#else
|
||||
@@ -12452,7 +12452,7 @@ void main() {
|
||||
return false;
|
||||
}
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith)
|
||||
if (MG_Config::DataArmIsRecord())
|
||||
return BeginWireXfbCaptureForDraw(frame);
|
||||
#endif
|
||||
const auto& program = MG_Pipe::gPipeInputs.GetTransformFeedbackProgram();
|
||||
@@ -13474,7 +13474,7 @@ void main() {
|
||||
vertexRange.instanceCount = 1;
|
||||
// MONOLITH ONLY: with a transport the frontend VAO is not this side's to read at all
|
||||
// (the client owns those bytes and stages them itself), and this runs on the apply thread.
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) {
|
||||
if (!MG_Config::DataArmIsRecord()) {
|
||||
const auto& currentVAO = MG_Pipe::gPipeInputs.GetBoundVertexArray();
|
||||
Bool clientArray = false;
|
||||
if (currentVAO) {
|
||||
@@ -13865,7 +13865,7 @@ void main() {
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
// Texture uploads submit on this queue with their own fences. The
|
||||
// renderer watermark alone cannot prove images/views are idle.
|
||||
if (m_textureManager && !m_textureManager->WireUploadsAreIdle()) return false;
|
||||
@@ -15344,7 +15344,7 @@ void main() {
|
||||
// CreateInstance requests Vulkan 1.1 on these platforms. A 1.2+ GPU
|
||||
// does not promote descriptor indexing into that application's core
|
||||
// API; the wire path must enable VK_EXT_descriptor_indexing instead.
|
||||
(MG_Config::Transport == MG_Config::TransportMode::Monolith) &&
|
||||
(!MG_Config::DataArmIsRecord()) &&
|
||||
#endif
|
||||
m_physicalDevice.properties.apiVersion >= VK_API_VERSION_1_2;
|
||||
const Bool descriptorIndexingExtension =
|
||||
@@ -15367,7 +15367,7 @@ void main() {
|
||||
m_physicalDevice.properties.apiVersion >= VK_API_VERSION_1_1 &&
|
||||
IsExtensionSupported(availableExtensions, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME) &&
|
||||
IsExtensionSupported(availableExtensions, VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
|
||||
const Bool wireDepthResolveEnabled = MG_Config::Transport != MG_Config::TransportMode::Monolith &&
|
||||
const Bool wireDepthResolveEnabled = MG_Config::DataArmIsRecord() &&
|
||||
getPhysicalDeviceProperties2 && (wireDepthResolveCore || wireDepthResolveExtensions);
|
||||
m_wireCreateRenderPass2 = nullptr;
|
||||
m_wireDepthResolveModes = m_wireStencilResolveModes = 0;
|
||||
@@ -15391,7 +15391,7 @@ void main() {
|
||||
// write the stencil aspect without it. Enabled on the same terms as the resolve
|
||||
// extensions above - wire arms only - and the arm declines stencil where it is absent
|
||||
// rather than producing an undefined aspect.
|
||||
m_wireShaderStencilExport = MG_Config::Transport != MG_Config::TransportMode::Monolith &&
|
||||
m_wireShaderStencilExport = MG_Config::DataArmIsRecord() &&
|
||||
IsExtensionSupported(availableExtensions, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
|
||||
if (m_wireShaderStencilExport)
|
||||
EnableOptionalDeviceExtension(availableExtensions, enabledDeviceExtensions,
|
||||
@@ -15408,7 +15408,7 @@ void main() {
|
||||
m_wireGetAhbProperties = nullptr;
|
||||
m_sharedImageSyncFd = false;
|
||||
#if defined(__ANDROID__)
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith &&
|
||||
if (MG_Config::DataArmIsRecord() &&
|
||||
m_physicalDevice.properties.apiVersion >= VK_API_VERSION_1_1 &&
|
||||
IsExtensionSupported(availableExtensions, VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME) &&
|
||||
IsExtensionSupported(availableExtensions, VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME)) {
|
||||
@@ -15963,7 +15963,7 @@ void main() {
|
||||
IsExtensionSupported(availableExtensions, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) ? VK_EXT_ROBUSTNESS_2_EXTENSION_NAME
|
||||
: IsExtensionSupported(availableExtensions, VK_KHR_ROBUSTNESS_2_EXTENSION_NAME) ? VK_KHR_ROBUSTNESS_2_EXTENSION_NAME
|
||||
: nullptr;
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith && robustness2Name != nullptr &&
|
||||
if (MG_Config::DataArmIsRecord() && robustness2Name != nullptr &&
|
||||
getPhysicalDeviceFeatures2 != nullptr) {
|
||||
VkPhysicalDeviceFeatures2 featureQuery{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
|
||||
featureQuery.pNext = &robustness2Features;
|
||||
@@ -15977,7 +15977,7 @@ void main() {
|
||||
m_wireNullDescriptor = true;
|
||||
}
|
||||
}
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
if (MG_Config::DataArmIsRecord()) {
|
||||
MGLOG_I("Magma wire: robustness2 nullDescriptor %s (%s)", m_wireNullDescriptor ? "enabled" : "unavailable",
|
||||
robustness2Name != nullptr ? robustness2Name : "no robustness2 extension");
|
||||
}
|
||||
@@ -16216,7 +16216,7 @@ void main() {
|
||||
// red when the real recording, readback or tally stops detecting it too.
|
||||
void VulkanRenderer::ArmWireDepthResolveOrder() {
|
||||
m_wirePreferShaderDepthResolve = false;
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) return;
|
||||
if (!MG_Config::DataArmIsRecord()) return;
|
||||
// ResolveWireDepthStencil's own test for the render-pass arm, less its per-format half
|
||||
// (the probe asks that per format): without it the shader pass is the only arm.
|
||||
const Bool renderPassArmAvailable = !MagmaWireForcedShaderDepthResolve() && m_wireCreateRenderPass2 &&
|
||||
|
||||
@@ -1251,8 +1251,12 @@ mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_HANDLES_ENVIRONMENT
|
||||
"MOBILEGL_TRANSPORT=monolith"
|
||||
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=handles" ${MGL_ITEST_HANDLES_ARM_KNOBS}
|
||||
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
|
||||
# P13 W4: THE ABA CONTROL'S SUBJECT IS THE FRONTEND ARM. The knob defeats the identity half of
|
||||
# Magma's frontend-arm keys (MagmaPipeIdentityTables); monolith's record arm keys every object on
|
||||
# the applier's {slot, gen}, which the knob does not - and must not - reach. So the lane pins the
|
||||
# frontend arm (MOBILEGL_PIPE_DATA_ARM, a W4-W6 knob) and goes with that arm in W6.
|
||||
mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_ABA_HANDLES_ENVIRONMENT
|
||||
"MOBILEGL_TRANSPORT=monolith"
|
||||
"MOBILEGL_TRANSPORT=monolith" "MOBILEGL_PIPE_DATA_ARM=frontend"
|
||||
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=aba"
|
||||
${MGL_ITEST_HANDLES_ARM_KNOBS} ${MGL_ITEST_ABA_ARM_KNOBS}
|
||||
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
|
||||
|
||||
@@ -109,7 +109,8 @@ void main() { o_color = texture(uTex, vec2(0.5)); }
|
||||
constexpr std::uint64_t kWireDescriptorSetBudget = 2048;
|
||||
std::uint64_t BurstSetsHeldAtOnce() {
|
||||
const std::uint64_t draws = static_cast<std::uint64_t>(kDraws);
|
||||
return PeekSplitRuntime().transportResolved ? std::min(draws, kWireDescriptorSetBudget) : draws;
|
||||
// The wire budget binds the RECORD arm, which monolith takes too from P13 W4.
|
||||
return PeekSplitRuntime().dataArmIsRecord ? std::min(draws, kWireDescriptorSetBudget) : draws;
|
||||
}
|
||||
|
||||
// Pools a geometric policy adds for n sets from an empty flavour: 64, 128, ... up to the cap,
|
||||
|
||||
@@ -73,6 +73,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
if (!Ready()) return;
|
||||
m_magma = Gl().BackendName() == "DirectVulkan";
|
||||
m_transport = PeekSplitRuntime().transportName;
|
||||
m_recordArm = PeekSplitRuntime().dataArmIsRecord;
|
||||
m_mark = CompileCompute(kMarkSource);
|
||||
ASSERT_NE(m_mark, 0u);
|
||||
m_copy = CompileCompute(kCopySource);
|
||||
@@ -192,7 +193,10 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
|
||||
// Magma's server in THIS process: the inproc arm. Spawn and tcp servers are other
|
||||
// processes, and the monolith arm never takes the wire path at all.
|
||||
bool CountersReadable() const { return m_magma && m_transport == "inproc"; }
|
||||
// The counters are this process's: inproc, and (P13 W4) monolith on the record arm.
|
||||
bool CountersReadable() const {
|
||||
return m_magma && (m_transport == "inproc" || (m_transport == "monolith" && m_recordArm));
|
||||
}
|
||||
|
||||
WireIndirectCounters Delta() const {
|
||||
WireIndirectCounters now{};
|
||||
@@ -209,6 +213,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
|
||||
bool m_magma = false;
|
||||
std::string m_transport;
|
||||
bool m_recordArm = false;
|
||||
WireIndirectCounters m_before{};
|
||||
GLuint m_mark = 0, m_copy = 0, m_groupCounts = 0, m_source = 0;
|
||||
std::vector<GLuint> m_marks;
|
||||
@@ -266,7 +271,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
// dependency here (P8-D recorded that half for dev), and Espryt's is its driver's.
|
||||
TEST_F(WireIndirectDispatchScenario, ShaderWrittenGroupCountsWithoutAnApplicationBarrierAreOrdered) {
|
||||
if (!Ready() || IsSkipped()) return;
|
||||
if (!m_magma || m_transport == "monolith") {
|
||||
if (!m_magma || !m_recordArm) {
|
||||
GTEST_SKIP() << "the implicit INDIRECT_COMMAND_READ barrier is the Magma wire arm's (P8-D, P8-SV)";
|
||||
}
|
||||
Parameters({1, 1, 1});
|
||||
|
||||
@@ -90,6 +90,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
if (!Ready()) return;
|
||||
m_magma = Gl().BackendName() == "DirectVulkan";
|
||||
m_transport = PeekSplitRuntime().transportName;
|
||||
m_recordArm = PeekSplitRuntime().dataArmIsRecord;
|
||||
std::string error;
|
||||
m_program = CompileProgram(kVertexSource, kFragmentSource, &error);
|
||||
ASSERT_NE(m_program, 0u) << error;
|
||||
@@ -203,7 +204,10 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
|
||||
// Magma's server in THIS process: the inproc arm. Spawn and tcp servers are other
|
||||
// processes, and the monolith arm never takes the wire path at all.
|
||||
bool CountersReadable() const { return m_magma && m_transport == "inproc"; }
|
||||
// The counters are this process's: inproc, and (P13 W4) monolith on the record arm.
|
||||
bool CountersReadable() const {
|
||||
return m_magma && (m_transport == "inproc" || (m_transport == "monolith" && m_recordArm));
|
||||
}
|
||||
|
||||
WireIndirectCounters Delta() const {
|
||||
WireIndirectCounters now{};
|
||||
@@ -215,6 +219,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
|
||||
bool m_magma = false;
|
||||
std::string m_transport;
|
||||
bool m_recordArm = false;
|
||||
WireIndirectCounters m_before{};
|
||||
GLuint m_program = 0, m_copy = 0, m_vao = 0, m_vbo = 0, m_ebo = 0;
|
||||
GLuint m_indirect = 0, m_parameter = 0, m_source = 0;
|
||||
@@ -304,7 +309,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
// monolith defects), left to P13 (ID-P8-13).
|
||||
TEST_F(WireIndirectDrawScenario, ComputeWrittenCountWordIsTheOneTheGpuReads) {
|
||||
if (!Ready() || IsSkipped()) return;
|
||||
if (!m_magma && m_transport == "monolith" && !PeekSplitRuntime().dataArmIsRecord) {
|
||||
if (!m_magma && !m_recordArm) {
|
||||
GTEST_SKIP() << "Espryt's monolith arm reads the count word from the frontend shadow without "
|
||||
"a sync (OQ15; recorded for P13, ID-P8-13)";
|
||||
}
|
||||
@@ -316,7 +321,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
glMultiDrawElementsIndirectCount(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0, 3, 0);
|
||||
});
|
||||
ExpectStrips(image, {true, false, false, false}, "glMultiDrawElementsIndirectCount, shader-written count 1");
|
||||
if (m_transport == "monolith") {
|
||||
if (!m_recordArm) {
|
||||
// DirectVulkan.cpp's monolith MultiDrawArraysIndirectCount reads this word from the
|
||||
// frontend shadow without SyncGpuWrites: recorded for dev (ID-P8-3), not this lane's.
|
||||
return;
|
||||
@@ -344,7 +349,7 @@ void main() { words[gl_GlobalInvocationID.x] = source[gl_GlobalInvocationID.x];
|
||||
// arm records no dependency here (recorded for dev), and Espryt's is its driver's.
|
||||
TEST_F(WireIndirectDrawScenario, ShaderWrittenCommandsWithoutAnApplicationBarrierAreOrdered) {
|
||||
if (!Ready() || IsSkipped()) return;
|
||||
if (!m_magma || m_transport == "monolith") {
|
||||
if (!m_magma || !m_recordArm) {
|
||||
GTEST_SKIP() << "the implicit INDIRECT_COMMAND_READ barrier is the Magma wire arm's (P8-D)";
|
||||
}
|
||||
Fill(m_indirect, GL_DRAW_INDIRECT_BUFFER, std::vector<ArraysCommand>{Arrays(3), Arrays(2)});
|
||||
|
||||
@@ -1435,7 +1435,7 @@ namespace MobileGL::MG_Pipe {
|
||||
// existing backend hooks authoritative when present, and use this fallback otherwise.
|
||||
void AdoptTextureWithoutBackendHook(const MGPipeResourceRecord& stored, const MGPSubData& upload,
|
||||
const void* bytes, const MGPSubRegion* regions) {
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith || !bytes || upload.Blob.Size == 0) return;
|
||||
if (!MG_Config::DataArmIsRecord() || !bytes || upload.Blob.Size == 0) return;
|
||||
auto& store = MG_Remote::Server::ServerStagedTexture();
|
||||
const auto& desc = stored.Desc;
|
||||
const Uint64 key = MG_Remote::Server::StagedTextureStore::KeyForHandle(upload.Res);
|
||||
@@ -1445,18 +1445,20 @@ namespace MobileGL::MG_Pipe {
|
||||
// is adopted with the spelling that replaces the level; every other record names a RUN
|
||||
// of the level by its own box (fix A2: a level too large to stage whole crosses as
|
||||
// slabs, one record each, and the first of them is at the level's first byte).
|
||||
// A client record's run: on monolith's record arm it is the frontend level shadow, which
|
||||
// an aliasing store keeps by address (P13 W4).
|
||||
if (upload.RegionCount == 0) {
|
||||
store.Adopt(key, target, upload.Level, extent, bytes,
|
||||
static_cast<SizeT>(upload.Blob.Size));
|
||||
static_cast<SizeT>(upload.Blob.Size), /*frontendShadow=*/true);
|
||||
return;
|
||||
}
|
||||
store.AdoptRun(key, target, upload.Level, extent,
|
||||
MG_Remote::Server::StagedTextureRunImageOffset(upload, regions), bytes,
|
||||
static_cast<SizeT>(upload.Blob.Size));
|
||||
static_cast<SizeT>(upload.Blob.Size), /*frontendShadow=*/true);
|
||||
}
|
||||
|
||||
void DefineTextureWithoutBackendHook(const MGPResourceDesc& desc, const MGPRespecifiedLevel* level) {
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) return;
|
||||
if (!MG_Config::DataArmIsRecord()) return;
|
||||
auto& store = MG_Remote::Server::ServerStagedTexture();
|
||||
const Uint64 key = MG_Remote::Server::StagedTextureStore::KeyForHandle(desc.Resource);
|
||||
const auto define = [&](Uint16 target, Uint16 mip, const IntVec3& extent) {
|
||||
@@ -1910,7 +1912,7 @@ namespace MobileGL::MG_Pipe {
|
||||
|
||||
void MGPipeApplierReleaseObjectRecords() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith &&
|
||||
if (MG_Config::DataArmIsRecord() &&
|
||||
(g_resourceOps == nullptr || g_resourceOps->TextureDestroy == nullptr)) {
|
||||
MG_Remote::Server::ServerStagedTexture().DropAll();
|
||||
}
|
||||
@@ -2686,7 +2688,7 @@ namespace MobileGL::MG_Pipe {
|
||||
if (static_cast<MGPipeKind>(handle.Kind) == MGPipeKind::Texture) {
|
||||
if (g_resourceOps != nullptr && g_resourceOps->TextureDestroy != nullptr)
|
||||
g_resourceOps->TextureDestroy(handle.Handle);
|
||||
else if (MG_Config::Transport != MG_Config::TransportMode::Monolith)
|
||||
else if (MG_Config::DataArmIsRecord())
|
||||
MG_Remote::Server::ServerStagedTexture().Drop(
|
||||
MG_Remote::Server::StagedTextureStore::KeyForHandle(handle.Handle));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user