//SPDX-License-Identifier: LGPL-3.0-only //SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // Regression test for issue #60: VulkanBuffer::FlushDevice / FlushHost used to // call vkFlushMappedMemoryRanges / vkInvalidateMappedMemoryRanges // unconditionally. They now record the *chosen* memory type's propertyFlags at // Create time and skip the flush/invalidate when the memory is HOST_COHERENT // (coherent memory makes host/device writes mutually visible with no explicit // flush). // // The gate is pure logic over the recorded flags, so this test drives it // directly with no GPU device: it stamps memoryPropertyFlagsChosen and verifies // the coherent path returns without issuing any Vulkan call. With no device // created, Device::device is VK_NULL_HANDLE — so if the gate were removed, the // flush call would dereference a null dispatch handle and crash. Reaching the // line after the calls is the assertion that the gate held. #include #include "vulkan/vulkan.h" import Crafter.Graphics; import std; using namespace Crafter; namespace { int failures = 0; void Check(bool ok, std::string_view what) { std::println("{} {}", ok ? "PASS" : "FAIL", what); if (!ok) ++failures; } constexpr auto DEVICE_LOCAL = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; constexpr auto HOST_VISIBLE = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; constexpr auto HOST_COHERENT = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; } // namespace int main() { // No device is created, so Device::device stays VK_NULL_HANDLE; any real // flush/invalidate call below would fault. The coherent gate must prevent // it. Check(Device::device == VK_NULL_HANDLE, "no Vulkan device created — a real flush would fault"); { VulkanBuffer buf; // Coherent type chosen (even though no COHERENT bit was requested): // both flush paths must early-return without touching Vulkan. buf.memoryPropertyFlagsChosen = HOST_VISIBLE | HOST_COHERENT; buf.FlushDevice(); buf.FlushHost(); Check(true, "FlushDevice/FlushHost skip the Vulkan call on coherent memory"); } { // A non-coherent type would require the flush — verify the recorded // flags reflect the gate's decision input rather than the request. The // bit test is the exact condition FlushDevice/FlushHost branch on. VulkanBuffer buf; buf.memoryPropertyFlagsChosen = HOST_VISIBLE | DEVICE_LOCAL; Check(!(buf.memoryPropertyFlagsChosen & HOST_COHERENT), "non-coherent chosen type is not gated as coherent (flush still required)"); } if (failures != 0) { std::println("{} check(s) failed", failures); return EXIT_FAILURE; } std::println("all checks passed"); return EXIT_SUCCESS; }