mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Fix, Test] (MG_State, MG_Backend/DirectVulkan, MG_Backend/DirectGLES, MG_IntegrationTest): a respecified capture buffer left the transform feedback writing one store and the readback reading another
This commit is contained in:
@@ -75,10 +75,39 @@ namespace MobileGL::MG_State::GLState {
|
||||
NotifySubData(offset, size);
|
||||
}
|
||||
|
||||
void BufferObject::Respecify(SizeT size, const void* data) {
|
||||
ReleaseMemory();
|
||||
// A (re)definition of the store is about to write `size` bytes through Bytes().
|
||||
// Sizing the shadow is all that takes for a shadow-backed buffer, but a buffer
|
||||
// whose bytes were adopted into backend GPU memory needs the adoption renewed
|
||||
// first: the mapping it holds describes exactly the OLD store. Writing the new
|
||||
// contents through it runs past its end the moment the store grows, and a backend
|
||||
// that replaces the storage for the new store (which is what an orphaning
|
||||
// respecification asks for) would leave that mapping - and therefore every later
|
||||
// read of this buffer - addressing storage nothing writes to any more.
|
||||
//
|
||||
// Renewing rather than simply dropping is what keeps the common case free: a
|
||||
// redefinition at the same size gets the same mapping back without any storage
|
||||
// being created, which is also what makes the backend's respecify a no-op (the
|
||||
// new bytes are already in the storage it would otherwise upload to).
|
||||
void BufferObject::RedefineStorage(SizeT size) {
|
||||
const Bool wasGpuResident = m_resource.IsGpuResident();
|
||||
if (wasGpuResident) {
|
||||
// A capture or a shader write may still be running against the very bytes
|
||||
// that are about to be overwritten.
|
||||
SyncGpuWrites();
|
||||
m_resource.ReleasePersistentMap();
|
||||
}
|
||||
m_size = size;
|
||||
m_resource.ResizeShadow(size);
|
||||
if (wasGpuResident) {
|
||||
// Declining is allowed (a zero-sized store, a backend without the op): the
|
||||
// buffer simply goes back to the CPU-shadow model it had before adoption.
|
||||
EnsureGpuResidentStorage();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferObject::Respecify(SizeT size, const void* data) {
|
||||
ReleaseMemory();
|
||||
RedefineStorage(size);
|
||||
if (data && size > 0) {
|
||||
Memcpy(m_resource.Bytes(), data, size);
|
||||
}
|
||||
@@ -96,8 +125,7 @@ namespace MobileGL::MG_State::GLState {
|
||||
|
||||
void BufferObject::AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags) {
|
||||
ReleaseMemory();
|
||||
m_size = size;
|
||||
m_resource.ResizeShadow(size);
|
||||
RedefineStorage(size);
|
||||
if (data) {
|
||||
Memcpy(m_resource.Bytes(), data, size);
|
||||
} else if (size > 0) {
|
||||
|
||||
@@ -205,6 +205,9 @@ namespace MobileGL {
|
||||
void SetBackendResource(SharedPtr<BackendBufferResource> resource);
|
||||
|
||||
private:
|
||||
// Sizes the store for a (re)definition, renewing an adopted GPU-resident
|
||||
// mapping across it. See the definition for why the renewal is not optional.
|
||||
void RedefineStorage(SizeT size);
|
||||
void NotifyRespecify();
|
||||
void NotifySubData(SizeT offset, SizeT size);
|
||||
void NotifyFlushMappedRange(Range1D range, Flags<BufferMappingAccessBit> appAccess);
|
||||
|
||||
@@ -70,6 +70,15 @@ namespace MobileGL::MG_State::GLState {
|
||||
m_shadow->shrink_to_fit();
|
||||
}
|
||||
|
||||
// Give the adoption back: the bytes resolve against the shadow again (which
|
||||
// the caller must (re)size, it was released on adoption). Used when the store
|
||||
// itself is redefined - the mapping describes exactly the store that is going
|
||||
// away, so it may neither be written through nor kept. It is NOT a general
|
||||
// "unmap": a persistent map the application holds outlives every unmap by
|
||||
// definition, and the calls that could redefine such a buffer's store are
|
||||
// errors the frontend refuses before reaching here.
|
||||
void ReleasePersistentMap() { m_gpuMapped = nullptr; }
|
||||
|
||||
// Backend GPU resource, owned here in both modes.
|
||||
const SharedPtr<BackendBufferResource>& Backend() const { return m_backend; }
|
||||
void SetBackend(SharedPtr<BackendBufferResource> backend) { m_backend = std::move(backend); }
|
||||
|
||||
Reference in New Issue
Block a user