[Fix] (MG_Backend/DirectVulkan, MG_Util): RenderPassEntry needs move assignment - robin-hood probing swaps entries, so mapped types must be swappable

This commit is contained in:
2026-08-12 00:11:55 -04:00
parent 8f3ce5f5b7
commit 7b946fd527
2 changed files with 36 additions and 0 deletions
@@ -101,6 +101,36 @@ namespace MobileGL::MG_Backend::DirectVulkan {
std::swap(layers, that.layers);
std::swap(lastUsedFrame, that.lastUsedFrame);
}
// Move ASSIGNMENT, not just construction. The destructor below suppresses the
// implicit one, which left the type move-constructible but not move-assignable -
// and therefore not swappable, which std::swap(pair&, pair&) requires. That was
// invisible while UnorderedMap only ever move-CONSTRUCTED an element into a fresh
// slot. ska::flat_hash_map probes robin-hood: inserting swaps the entry being
// placed against the one already sitting in the slot whenever it has travelled
// further from its desired position, so the mapped type has to be swappable or the
// whole table fails to instantiate.
//
// Swap-based, exactly like the move constructor: our old handles land in `that`
// and are destroyed when it dies, so ownership stays with a single object and no
// VkRenderPass/VkFramebuffer is leaked or double-destroyed.
RenderPassEntry& operator=(RenderPassEntry&& that) noexcept {
if (this != &that) {
std::swap(hash, that.hash);
std::swap(renderPass, that.renderPass);
std::swap(framebuffer, that.framebuffer);
std::swap(compatibilityHash, that.compatibilityHash);
std::swap(pendingClearAttachments, that.pendingClearAttachments);
std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts);
std::swap(attachmentCount, that.attachmentCount);
std::swap(colorAttachmentCount, that.colorAttachmentCount);
std::swap(hasDepthStencilAttachment, that.hasDepthStencilAttachment);
std::swap(sampleCount, that.sampleCount);
std::swap(extent, that.extent);
std::swap(layers, that.layers);
std::swap(lastUsedFrame, that.lastUsedFrame);
}
return *this;
}
RenderPassEntry(
Uint64 hash,
VkRenderPass renderpass,
+6
View File
@@ -69,6 +69,12 @@ namespace MobileGL {
// compiles and silently corrupts the table - the one sharp edge this map has
// that a node-based one does not. Note the Allocator default matches that
// value_type: pair<Key, T>, not pair<const Key, T>.
//
// T must be move-ASSIGNABLE, not merely move-constructible: robin-hood probing
// swaps the entry being inserted against the one already in the slot whenever it
// has travelled further from its desired position. A move-only RAII type that
// declares a destructor gets no implicit move assignment, so it needs an explicit
// one or the table will not instantiate (see RenderPassEntry).
template <typename Key, typename T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key, T>>>
using UnorderedMap = ska::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>;