diff --git a/runtime/ui/menu_art.cpp b/runtime/ui/menu_art.cpp index 3a623ca0..ad7f31f8 100644 --- a/runtime/ui/menu_art.cpp +++ b/runtime/ui/menu_art.cpp @@ -134,6 +134,11 @@ static int upload_rgba(Art &a, const uint8_t *rgba, uint32_t w, uint32_t h, uint } memcpy(map, chain, (size_t)bytes); free(chain); + // The batch flushes its own staging buffers. This one is caller-owned and can be noncoherent. + if (vmaFlushAllocation(c->vma, sa, 0, bytes) != VK_SUCCESS) { + vmaDestroyBuffer(c->vma, sb, sa); + return art_free(a), 0; + } VkCommandBuffer cb = vk_upload_begin(); VkImageMemoryBarrier2 b = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; b.srcStageMask = VK_PIPELINE_STAGE_2_NONE; diff --git a/runtime/vk_astc.c b/runtime/vk_astc.c index daa4e5b9..04bda92b 100644 --- a/runtime/vk_astc.c +++ b/runtime/vk_astc.c @@ -483,13 +483,19 @@ static VkBuffer scratch_get(VkCtx *c, VkCommandBuffer cb, VkDeviceSize need, int VmaAllocationCreateInfo aci = {.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE}; VkBuffer b; VmaAllocation a; - if (vmaCreateBuffer(c->vma, &bi, &aci, &b, &a, NULL) != VK_SUCCESS) { + VkResult r = vmaCreateBuffer(c->vma, &bi, &aci, &b, &a, NULL); + if (r == VK_ERROR_OUT_OF_DEVICE_MEMORY && bi.size > need) { + // The usual scratch leaves room for later textures. This upload can still fit without the spare bytes. + bi.size = need; + r = vmaCreateBuffer(c->vma, &bi, &aci, &b, &a, NULL); + } + if (r != VK_SUCCESS) { plat_mutex_unlock(&g_lock); return VK_NULL_HANDLE; } // the old one may still be read by its command buffer: freed once the batches recorded so far completed if (S.buf && S.dev == c->device) vk_defer_buffer(S.buf, S.alloc); - S.buf = b, S.alloc = a, S.size = size, S.dev = c->device; + S.buf = b, S.alloc = a, S.size = bi.size, S.dev = c->device; n_scratch_new++; vk_texstat_time(VK_TS_SCRATCH, t0); } else { diff --git a/runtime/vk_memory.c b/runtime/vk_memory.c index 1c17fd59..5574d9c6 100644 --- a/runtime/vk_memory.c +++ b/runtime/vk_memory.c @@ -3679,6 +3679,12 @@ void *vk_staging(VkDeviceSize size, VkBuffer *buf, VmaAllocation *alloc) { VkBuffer b; VmaAllocation a; VkResult r = vmaCreateBuffer(c->vma, &bi, &aci, &b, &a, &info); + if (r == VK_ERROR_OUT_OF_DEVICE_MEMORY && aci.pool) { + // The staging pool can grow only in 64 MiB blocks of its one memory type. A smaller allocation may + // still fit in a default block or another host-visible type. Keep the same mapping requirements. + aci.pool = NULL; + r = vmaCreateBuffer(c->vma, &bi, &aci, &b, &a, &info); + } if (r != VK_SUCCESS) rt_fatal("vk: staging buffer of %llu bytes failed (%d)", (unsigned long long)size, (int)r); vk_texstat_add(VK_TS_STG_NEW, 1, bi.size); *buf = b;