[MG_Backend] (Disaggregated): P5f fm - fence remaining buffer debt and preserve native transfer layouts

This commit is contained in:
2026-09-19 22:40:04 -04:00
parent fec49a54d8
commit 6a138a5221
6 changed files with 90 additions and 15 deletions
@@ -32,6 +32,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
UniquePtr<VulkanRenderer>& pVulkanRenderer = *new UniquePtr<VulkanRenderer>();
namespace {
#if MOBILEGL_BUILD_DISAGGREGATED
void RejectWireLegacyBuffer() {
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
MGLOG_F("MGPipe: Fatal{RoleViolation, \"buffer-legacy-arm\"} (Magma P7 buffer consumer)");
std::abort();
}
}
#else
inline void RejectWireLegacyBuffer() {}
#endif
// Generation of the live VulkanRenderer instance, mirroring
// DirectGLES's g_syncContextGeneration. BackendObject_DirectVulkan
// bumps it (BumpRendererGeneration) wherever pVulkanRenderer is reset
@@ -391,11 +401,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElementsIndirect called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
}
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawArraysIndirect called with null GL context");
@@ -447,12 +463,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawArraysIndirectCount called with null GL context");
@@ -525,6 +547,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
DrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, instancecount, 0, 0);
}
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawElementsIndirect called with null GL context");
@@ -584,6 +609,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
DrawArraysInstancedBaseInstance(mode, first, count, instancecount, 0);
}
void DrawArraysIndirect(GLenum mode, const void* indirect) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawArraysIndirect called with null GL context");
@@ -652,6 +680,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
void DispatchComputeIndirect(GLintptr indirect) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DispatchComputeIndirect called with null GL context");
pVulkanRenderer->DispatchComputeIndirect(indirect);
@@ -817,6 +848,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// memory) into uint32 values with the loop-closing first index appended.
static Bool BuildClosedLineLoopIndices(GLsizei count, GLenum type, const void* indices,
Vector<Uint32>& outIndices) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
const SizeT indexSize = MG_Util::GetGLTypeSize(type);
if (indexSize == 0 || count < 2) {
return false;
@@ -932,6 +966,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// vkCmdDrawIndexed all carry natively.
static void MultiDrawElementsImpl(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) {
#if MOBILEGL_BUILD_DISAGGREGATED
RejectWireLegacyBuffer();
#endif
if (drawcount <= 0) {
return;
}
@@ -6869,7 +6869,7 @@ void main() {
const IndexBufferView* pIndexBufferView) {
#if MOBILEGL_BUILD_DISAGGREGATED
if (MG_Config::Transport != MG_Config::TransportMode::Monolith)
return SetupWireDraw(frame, mode, aspects, drawParams);
return SetupWireDraw(frame, mode, aspects, drawParams, pIndexBufferView);
#endif
// Sync each sampled texture at most once across this whole draw: the layout
// probe loop, the post-transition loop, and ResolveSamplerDescriptor would
@@ -11226,7 +11226,13 @@ void main() {
}
// Store honoring the client pack state (single slice).
#if MOBILEGL_BUILD_DISAGGREGATED
const SharedPtr<MG_State::GLState::BufferObject> wireReplyHasNoPackBuffer;
#endif
const auto& pixelPackBufferObject =
#if MOBILEGL_BUILD_DISAGGREGATED
MG_Config::Transport != MG_Config::TransportMode::Monolith ? wireReplyHasNoPackBuffer :
#endif
MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
const auto packParams = MGB_CTX->GetPixelStoreParameters(false);
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
@@ -458,7 +458,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
GLenum format, GLenum type, void* pixels);
void GenerateWireMipmap();
Bool SetupWireDraw(FrameContext::FrameData& frame, GLenum mode, Flags<DrawSetupAspect> aspects,
const DrawCmdParam& drawParams);
const DrawCmdParam& drawParams, const IndexBufferView* indices);
void DestroyWireDrawPass();
void DispatchWireCompute(GLuint x, GLuint y, GLuint z);
UniquePtr<RenderPassEntry> m_wireDrawPass;
@@ -23,11 +23,12 @@
}
Bool VulkanRenderer::SetupWireDraw(FrameContext::FrameData& frame, GLenum mode,
Flags<DrawSetupAspect> aspects, const DrawCmdParam& drawParams) {
Flags<DrawSetupAspect> aspects, const DrawCmdParam& drawParams, const IndexBufferView* indices) {
auto& state = MG_Pipe::MGPipeApplier();
const auto program = WireProgramSource(state.BoundShaderCso);
if (!program.GetLinkStatus() || !program.GetSpirvStatus()) return false;
if (aspects & DrawSetupAspect::IndexBuffer || aspects & DrawSetupAspect::IndirectDrawBuffer ||
if (((aspects & DrawSetupAspect::IndexBuffer) && (!indices || !indices->forceClientMemory)) ||
aspects & DrawSetupAspect::IndirectDrawBuffer ||
MGB_CTX->IsTransformFeedbackActive()) WireBufferLegacyFatal();
const auto* fbo = state.DrawFramebuffer();
if (!fbo) MagmaWireFatal("draw-framebuffer-record");
@@ -43,6 +44,7 @@
if (programObject->pointSizeCapabilityUnsupported) return false;
const auto& programObj = *programObject;
const auto vaoHandle = state.BoundVertexElements;
if (MG_Pipe::MGPipeHandleIsNull(vaoHandle)) MagmaWireFatal("vertex-elements-record");
if (!MG_Pipe::MGPipeHandleIsNull(vaoHandle)) {
if (vaoHandle.Slot >= state.VertexElementsCsos.size()) MagmaWireFatal("vertex-elements-record");
const auto& vao = state.VertexElementsCsos[vaoHandle.Slot];
@@ -55,7 +57,7 @@
Vector<VkAttachmentDescription> attachments;
Vector<VkImageView> views;
Vector<VkAttachmentReference> colors;
VkAttachmentReference depth{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkAttachmentReference depth{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL};
VkExtent2D extent{~0u, ~0u};
Uint32 layers = ~0u;
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
@@ -65,7 +67,7 @@
if (!image.image) return VK_ATTACHMENT_UNUSED;
m_textureManager->FlushPendingUploads();
const VkImageLayout layout = aspect == VK_IMAGE_ASPECT_COLOR_BIT ?
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_GENERAL;
TransitionWireImage(image, layout);
VkImageViewCreateInfo info{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
info.image = image.image;
@@ -101,7 +103,7 @@
for (Uint32 i = 0; i < MG_Pipe::kMGPipeMaxColorAttachments; ++i) {
const Int32 slot = fbo->DrawBuffers[i];
const Uint32 index = slot < 0 ? VK_ATTACHMENT_UNUSED : add(fbo->Color[slot], VK_IMAGE_ASPECT_COLOR_BIT);
colors.push_back({index, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
colors.push_back({index, VK_IMAGE_LAYOUT_GENERAL});
}
while (!colors.empty() && colors.back().attachment == VK_ATTACHMENT_UNUSED) colors.pop_back();
if (fbo->IsDefault || fbo->Depth.Kind != MG_Pipe::kMGPipeSurfaceKindNone)
@@ -154,6 +156,14 @@
data, size, 16, slice)) return false;
vkCmdBindVertexBuffers(frame.commandBuffer, binding++, 1, &slice.buffer, &slice.offset);
}
if (indices) {
BufferSlice slice{};
if (!m_bufferManager.UploadTransient(BufferKind::Index, m_frameContext.GetCurrentFrameIndex(),
reinterpret_cast<const void*>(indices->indexByteOffset), indices->indexByteSize, 16, slice)) return false;
const VkIndexType type = indices->indexType == GL_UNSIGNED_INT ? VK_INDEX_TYPE_UINT32 :
indices->indexType == GL_UNSIGNED_SHORT ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT8;
vkCmdBindIndexBuffer(frame.commandBuffer, slice.buffer, slice.offset, type);
}
if (!VkRenderPassManager::BeginRenderPass(frame.commandBuffer, pass)) return false;
vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
ApplyDynamicDrawStateTail(frame, pass.extent, fbo->IsDefault,
@@ -283,9 +283,27 @@
region.dstOffsets[0].y = static_cast<GLint>(destination.extent.height)-dy0;
region.dstOffsets[1].y = static_cast<GLint>(destination.extent.height)-dy1;
}
vkCmdBlitImage(m_frameContext.GetCurrent().commandBuffer,source.image,srcLayout,
destination.image,dstLayout,1,&region,
filter == GL_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
auto command = m_frameContext.GetCurrent().commandBuffer;
if (source.samples != VK_SAMPLE_COUNT_1_BIT || destination.samples != VK_SAMPLE_COUNT_1_BIT) {
const Int32 width = region.srcOffsets[1].x - region.srcOffsets[0].x;
const Int32 height = region.srcOffsets[1].y - region.srcOffsets[0].y;
if (width <= 0 || height <= 0 || width != region.dstOffsets[1].x - region.dstOffsets[0].x ||
height != region.dstOffsets[1].y - region.dstOffsets[0].y || source.format != destination.format)
MagmaWireFatal("multisample-blit-shape@P7");
if (source.samples != VK_SAMPLE_COUNT_1_BIT && destination.samples == VK_SAMPLE_COUNT_1_BIT &&
aspect == VK_IMAGE_ASPECT_COLOR_BIT) {
VkImageResolve resolve{region.srcSubresource, region.srcOffsets[0],
region.dstSubresource, region.dstOffsets[0], {static_cast<Uint32>(width), static_cast<Uint32>(height), 1}};
vkCmdResolveImage(command, source.image, srcLayout, destination.image, dstLayout, 1, &resolve);
} else if (source.samples == destination.samples) {
VkImageCopy copy{region.srcSubresource, region.srcOffsets[0], region.dstSubresource,
region.dstOffsets[0], {static_cast<Uint32>(width), static_cast<Uint32>(height), 1}};
vkCmdCopyImage(command, source.image, srcLayout, destination.image, dstLayout, 1, &copy);
} else MagmaWireFatal("multisample-blit-aspect@P7");
} else {
vkCmdBlitImage(command,source.image,srcLayout,destination.image,dstLayout,1,&region,
filter == GL_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
}
if (!destination.isDefault && dst.Kind == MG_Pipe::kMGPipeSurfaceKindTexture)
m_textureManager->MarkWireTextureGpuWritten(destination.storage, destination.level, destination.layer, destination.layers);
if (destination.isDefault) {
@@ -328,8 +346,12 @@
WireImage destination = ResolveWireImage(fake,surface,aspect);
if (!source.image || !destination.image) return;
m_textureManager->FlushPendingUploads();
TransitionWireImage(source,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
TransitionWireImage(destination,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
const Bool sameImage = source.image == destination.image;
const VkImageLayout srcLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
const VkImageLayout dstLayout = sameImage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
TransitionWireImage(source,srcLayout);
if (sameImage) destination.layout = source.layout;
else TransitionWireImage(destination,dstLayout);
VkImageBlit region{};
region.srcSubresource = {aspect,source.level,source.layer,1};
region.dstSubresource = {aspect,destination.level,destination.layer,1};
@@ -339,8 +361,8 @@
region.srcOffsets[0].y = static_cast<Int32>(source.extent.height)-y;
region.srcOffsets[1].y = static_cast<Int32>(source.extent.height)-y-height;
}
vkCmdBlitImage(m_frameContext.GetCurrent().commandBuffer,source.image,VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
destination.image,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,1,&region,VK_FILTER_NEAREST);
vkCmdBlitImage(m_frameContext.GetCurrent().commandBuffer,source.image,srcLayout,
destination.image,dstLayout,1,&region,VK_FILTER_NEAREST);
m_textureManager->MarkWireTextureGpuWritten(destination.storage,destination.level,destination.layer);
}
+1 -1
View File
@@ -2386,7 +2386,7 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
foreach(fmSlot PartialTextureUploadPreservesGpuClear TextureViewClearTargetsItsRootMipAndLayer ClearBufferfi ClearBufferfv ClearBufferiv ClearBufferuiv ClearNamedFramebufferfi ClearNamedFramebufferfv ClearNamedFramebufferiv ClearNamedFramebufferuiv CopyTexImage2D CopyTexSubImage2D GenerateMipmap GenerateMipmapPackedFloat GenerateMipmapDepth)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.Split.Fm."
TEST_FILTER "F1WireScenario.${fmSlot}Pixels"
TEST_FILTER "F1WireScenario.${fmSlot}*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS "integration-magma-split"