mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-14 05:23:23 +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
|
// End of Source File Header
|
||||||
|
|
||||||
#include "VulkanRenderer.h"
|
#include "VulkanRenderer.h"
|
||||||
|
#include "SubmitFencePrefix.h"
|
||||||
|
|
||||||
#include "MG_Backend/DirectVulkan/SubgroupSupportPolicy.h"
|
#include "MG_Backend/DirectVulkan/SubgroupSupportPolicy.h"
|
||||||
#include "MG_Backend/DirectGLES/Utils.h"
|
#include "MG_Backend/DirectGLES/Utils.h"
|
||||||
@@ -13679,12 +13680,8 @@ void main() {
|
|||||||
if (submitIndex <= m_completedSubmitCounter) return true;
|
if (submitIndex <= m_completedSubmitCounter) return true;
|
||||||
if (submitIndex > m_submitCounter || m_device == VK_NULL_HANDLE) return false;
|
if (submitIndex > m_submitCounter || m_device == VK_NULL_HANDLE) return false;
|
||||||
Vector<VkFence> fences;
|
Vector<VkFence> fences;
|
||||||
for (const auto& record : m_inFlightSubmits) {
|
if (!CollectSubmitFencePrefix(m_inFlightSubmits, submitIndex, VkFence{}, fences))
|
||||||
if (record.submitIndex > submitIndex) break;
|
return false;
|
||||||
if (record.fence == VK_NULL_HANDLE) return false;
|
|
||||||
fences.push_back(record.fence);
|
|
||||||
}
|
|
||||||
if (fences.empty()) return false;
|
|
||||||
const VkResult result = vkWaitForFences(m_device, static_cast<Uint32>(fences.size()),
|
const VkResult result = vkWaitForFences(m_device, static_cast<Uint32>(fences.size()),
|
||||||
fences.data(), VK_TRUE, timeoutNs);
|
fences.data(), VK_TRUE, timeoutNs);
|
||||||
if (result == VK_SUCCESS) {
|
if (result == VK_SUCCESS) {
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ namespace MobileGL::MG_Impl::GLXImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ContextObject {
|
struct ContextObject {
|
||||||
Display* XDisplay = nullptr;
|
::Display* XDisplay = nullptr;
|
||||||
EGLDisplay Display = EGL_NO_DISPLAY;
|
EGLDisplay Display = EGL_NO_DISPLAY;
|
||||||
EGLConfig Config = nullptr;
|
EGLConfig Config = nullptr;
|
||||||
EGLContext Context = EGL_NO_CONTEXT;
|
EGLContext Context = EGL_NO_CONTEXT;
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ if (MSVC)
|
|||||||
target_compile_options(PipeCatalogueTest PRIVATE /Zc:preprocessor)
|
target_compile_options(PipeCatalogueTest PRIVATE /Zc:preprocessor)
|
||||||
endif()
|
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
|
# 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
|
# 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
|
# 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