mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[MG_Backend, MG_Test] (P7): prove aggregate waits with a single-fence control
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/SubmitFencePrefix.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// Collect every fence in the ordered submission prefix. Waiting on only the last matching
|
||||
// frame-serial record is insufficient: the same serial may have an earlier in-flight submit.
|
||||
template <typename Records, typename Fence>
|
||||
bool CollectSubmitFencePrefix(const Records& records, std::uint64_t submitIndex,
|
||||
Fence nullFence, std::vector<Fence>& fences) {
|
||||
fences.clear();
|
||||
bool foundTarget = false;
|
||||
for (const auto& record : records) {
|
||||
if (record.submitIndex > submitIndex) {
|
||||
break;
|
||||
}
|
||||
if (record.fence == nullFence) {
|
||||
fences.clear();
|
||||
return false;
|
||||
}
|
||||
fences.push_back(record.fence);
|
||||
foundTarget = foundTarget || record.submitIndex == submitIndex;
|
||||
}
|
||||
if (!foundTarget) {
|
||||
fences.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
@@ -7,6 +7,7 @@
|
||||
// End of Source File Header
|
||||
|
||||
#include "VulkanRenderer.h"
|
||||
#include "SubmitFencePrefix.h"
|
||||
|
||||
#include "MG_Backend/DirectVulkan/SubgroupSupportPolicy.h"
|
||||
#include "MG_Backend/DirectGLES/Utils.h"
|
||||
@@ -13679,12 +13680,8 @@ void main() {
|
||||
if (submitIndex <= m_completedSubmitCounter) return true;
|
||||
if (submitIndex > m_submitCounter || m_device == VK_NULL_HANDLE) return false;
|
||||
Vector<VkFence> fences;
|
||||
for (const auto& record : m_inFlightSubmits) {
|
||||
if (record.submitIndex > submitIndex) break;
|
||||
if (record.fence == VK_NULL_HANDLE) return false;
|
||||
fences.push_back(record.fence);
|
||||
}
|
||||
if (fences.empty()) return false;
|
||||
if (!CollectSubmitFencePrefix(m_inFlightSubmits, submitIndex, VkFence{}, fences))
|
||||
return false;
|
||||
const VkResult result = vkWaitForFences(m_device, static_cast<Uint32>(fences.size()),
|
||||
fences.data(), VK_TRUE, timeoutNs);
|
||||
if (result == VK_SUCCESS) {
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace MobileGL::MG_Impl::GLXImpl {
|
||||
}
|
||||
|
||||
struct ContextObject {
|
||||
Display* XDisplay = nullptr;
|
||||
::Display* XDisplay = nullptr;
|
||||
EGLDisplay Display = EGL_NO_DISPLAY;
|
||||
EGLConfig Config = nullptr;
|
||||
EGLContext Context = EGL_NO_CONTEXT;
|
||||
|
||||
@@ -24,6 +24,12 @@ if (MSVC)
|
||||
target_compile_options(PipeCatalogueTest PRIVATE /Zc:preprocessor)
|
||||
endif()
|
||||
|
||||
# P7 B4 aggregate-wait regression control shares the production selector; no device is needed.
|
||||
add_executable(MagmaAggregateWaitTest MagmaAggregateWaitTest.cpp)
|
||||
target_include_directories(MagmaAggregateWaitTest PRIVATE ${MGL_ROOT}/include ${MGL_ROOT}/MobileGL)
|
||||
target_link_libraries(MagmaAggregateWaitTest PRIVATE GTest::gtest_main ${LINK_LIBRARIES})
|
||||
gtest_discover_tests(MagmaAggregateWaitTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit)
|
||||
|
||||
# The P1 poison and verify shapes at the block level: a fake GLContext, the real filler and
|
||||
# accessors out of the static library. Links gtest (not gtest_main): the suite needs its own
|
||||
# main() to point MOBILEGL_LOG_FILE_PATH at a temp file before anything logs, because its
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// MobileGL - MobileGL/MG_Test/Pipe/MagmaAggregateWaitTest.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
// Deterministic, device-free control for P7 B4's aggregate submit wait. Production and this
|
||||
// test share CollectSubmitFencePrefix: two submissions can carry one frame serial, so the
|
||||
// targeted serial stays incomplete when the old single-fence control retires only one.
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <MG_Backend/DirectVulkan/Renderer/SubmitFencePrefix.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
using MobileGL::MG_Backend::DirectVulkan::CollectSubmitFencePrefix;
|
||||
|
||||
struct Submit {
|
||||
std::uint64_t submitIndex;
|
||||
std::uint64_t frameSerial;
|
||||
int fence;
|
||||
};
|
||||
|
||||
bool SerialComplete(std::uint64_t serial, const std::vector<Submit>& pending) {
|
||||
return std::none_of(pending.begin(), pending.end(), [serial](const Submit& submit) {
|
||||
return submit.frameSerial == serial;
|
||||
});
|
||||
}
|
||||
|
||||
TEST(MagmaAggregateWaitTest, MissingTargetAfterAnEarlierPrefixIsRejected) {
|
||||
const std::vector<Submit> gap{{10, 42, 101}, {12, 43, 103}};
|
||||
std::vector<int> fences;
|
||||
|
||||
EXPECT_FALSE(CollectSubmitFencePrefix(gap, 11, 0, fences));
|
||||
EXPECT_TRUE(fences.empty());
|
||||
}
|
||||
|
||||
TEST(MagmaAggregateWaitTest, SingleFenceControlLeavesTheTargetFrameInFlight) {
|
||||
const std::vector<Submit> pending{{10, 42, 101}, {11, 42, 102}, {12, 43, 103}};
|
||||
|
||||
// The old control waits only the first matching fence. The second submit still carries 42.
|
||||
auto singleFenceControl = pending;
|
||||
singleFenceControl.erase(singleFenceControl.begin());
|
||||
EXPECT_FALSE(SerialComplete(42, singleFenceControl));
|
||||
|
||||
// The production selector includes both submissions through index 11, but not frame 43.
|
||||
std::vector<int> fences;
|
||||
ASSERT_TRUE(CollectSubmitFencePrefix(pending, 11, 0, fences));
|
||||
ASSERT_EQ(fences, (std::vector<int>{101, 102}));
|
||||
|
||||
auto aggregateWait = pending;
|
||||
aggregateWait.erase(
|
||||
std::remove_if(aggregateWait.begin(), aggregateWait.end(), [&fences](const Submit& submit) {
|
||||
return std::find(fences.begin(), fences.end(), submit.fence) != fences.end();
|
||||
}),
|
||||
aggregateWait.end());
|
||||
EXPECT_TRUE(SerialComplete(42, aggregateWait));
|
||||
ASSERT_EQ(aggregateWait.size(), 1u);
|
||||
EXPECT_EQ(aggregateWait.front().frameSerial, 43u);
|
||||
}
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user