mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
Compare commits
2
Commits
e4aab8d0bc
...
2afeec95cd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2afeec95cd | ||
|
|
a2801f9da4 |
@@ -4421,6 +4421,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A SLOT THAT HAS NOT ACQUIRED STILL HOLDS ITS FENCE SIGNALED. The slot fences are created
|
||||
// signaled and only WaitAndAcquireNextImage resets them, so while the first acquire is
|
||||
// deferred (no swapchain yet: a zero-area or hidden window, which is what an offscreen
|
||||
// context created through a helper window is) the current slot's fence is still signaled
|
||||
// here. Submitting it in that state is invalid (VUID-vkQueueSubmit-fence-00063), and in
|
||||
// practice the wait below then returns at once - before the copy has run - so the readback
|
||||
// hands back the buffer's initial zeros. The late signal from that submission could also
|
||||
// land after the reset below, leaving the NEXT readback to submit a signaled fence again.
|
||||
//
|
||||
// Such a fence is unsignaled before the submit, and handed back signaled afterwards: the
|
||||
// deferred acquire (Present) waits on it with no submission of its own, and a fence this
|
||||
// readback reset and left unsignaled would never signal for that wait.
|
||||
const Bool slotFenceIdle = vkGetFenceStatus(m_device, frame.imageInFlightFence) == VK_SUCCESS;
|
||||
if (slotFenceIdle) {
|
||||
const VkResult resetResult = vkResetFences(m_device, 1, &frame.imageInFlightFence);
|
||||
if (resetResult != VK_SUCCESS) {
|
||||
MGLOG_E_ONCE("DirectVulkan readback: vkResetFences on the idle slot fence returned %d", resetResult);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SubmitPendingCommandBuffer(frame, frame.imageInFlightFence, /*pooledFence=*/false)) {
|
||||
return false;
|
||||
}
|
||||
@@ -4468,10 +4489,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
OnSubmitsCompletedUpTo(frame.lastSubmitIndex);
|
||||
result = vkResetFences(m_device, 1, &frame.imageInFlightFence);
|
||||
if (result != VK_SUCCESS) {
|
||||
MGLOG_E_ONCE("DirectVulkan readback: vkResetFences returned %d", result);
|
||||
return false;
|
||||
if (!slotFenceIdle) {
|
||||
result = vkResetFences(m_device, 1, &frame.imageInFlightFence);
|
||||
if (result != VK_SUCCESS) {
|
||||
MGLOG_E_ONCE("DirectVulkan readback: vkResetFences returned %d", result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
frame.hasCommandBufferRecorded = false;
|
||||
|
||||
@@ -348,8 +348,16 @@ namespace {
|
||||
void* EGLAPIENTRY VendorGetDispatchAddress(const char* procName) { return LookupEntryPoint(procName); }
|
||||
} // namespace
|
||||
|
||||
extern "C" MOBILEGL_EGL_API EGLBoolean __egl_Main(uint32_t version, const __EGLapiExports* exports,
|
||||
__EGLvendorInfo* vendor, __EGLapiImports* imports) {
|
||||
// libeglabi.h has already declared this prototype without an export attribute, and MSVC refuses a
|
||||
// redeclaration that adds dllexport. Windows has no glvnd to look the symbol up, so it is a plain
|
||||
// external definition there.
|
||||
#ifdef _WIN32
|
||||
#define MOBILEGL_GLVND_EGL_MAIN extern "C"
|
||||
#else
|
||||
#define MOBILEGL_GLVND_EGL_MAIN MOBILEGL_EGL_API
|
||||
#endif
|
||||
MOBILEGL_GLVND_EGL_MAIN EGLBoolean __egl_Main(uint32_t version, const __EGLapiExports* exports,
|
||||
__EGLvendorInfo* vendor, __EGLapiImports* imports) {
|
||||
(void)vendor;
|
||||
if (EGL_VENDOR_ABI_GET_MAJOR_VERSION(version) != EGL_VENDOR_ABI_MAJOR_VERSION) {
|
||||
// A vendor that does not know the ABI it is being handed must say so, not guess: the
|
||||
|
||||
@@ -1634,7 +1634,7 @@ namespace MobileGL::MG_Pipe {
|
||||
rectBoxes, rectCount, slab, pitch, m_regions.data(), m_regions.size());
|
||||
m_regions.resize(pieceRegions);
|
||||
fillRecord(slab.Box,
|
||||
reinterpret_cast<Uint64>(reinterpret_cast<std::uintptr_t>(shadow)) +
|
||||
static_cast<Uint64>(reinterpret_cast<std::uintptr_t>(shadow)) +
|
||||
slab.RunOffset);
|
||||
const Bool pieceAccepted = emitRecord(
|
||||
static_cast<const Uint8*>(shadow) + slab.RunOffset, slab.RunBytes);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <Config.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
@@ -1012,7 +1013,7 @@ namespace MobileGL::MG_Record {
|
||||
for (SizeT wordIndex = 0; wordIndex < (tracked->pageCount + 63) / 64; ++wordIndex) {
|
||||
Uint64 word = tracked->pageBits[wordIndex].load(std::memory_order_relaxed);
|
||||
while (word != 0) {
|
||||
const SizeT bit = static_cast<SizeT>(__builtin_ctzll(word));
|
||||
const SizeT bit = static_cast<SizeT>(std::countr_zero(word));
|
||||
word &= word - 1;
|
||||
const SizeT pageIndex = (wordIndex << 6) + bit;
|
||||
// Clear the bit FIRST, per the order the correctness argument
|
||||
@@ -1026,7 +1027,7 @@ namespace MobileGL::MG_Record {
|
||||
std::memory_order_relaxed);
|
||||
SizeT runEnd = pageIndex + 1;
|
||||
while (word != 0) {
|
||||
const SizeT nextBit = static_cast<SizeT>(__builtin_ctzll(word));
|
||||
const SizeT nextBit = static_cast<SizeT>(std::countr_zero(word));
|
||||
if ((wordIndex << 6) + nextBit != runEnd) break;
|
||||
word &= word - 1;
|
||||
tracked->pageBits[wordIndex].fetch_and(~(1ull << nextBit),
|
||||
|
||||
Reference in New Issue
Block a user