//SPDX-License-Identifier: LGPL-3.0-only //SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // VulkanBuffer::Create asks for a device address only for buffers whose // usage includes SHADER_DEVICE_ADDRESS. It used to request the // DEVICE_ADDRESS allocation flag and call vkGetBufferDeviceAddress for every // buffer, which is invalid usage for the others // (VUID-VkBufferDeviceAddressInfo-buffer-02601), so every caller had to add // the usage bit whether it wanted an address or not. A buffer without the bit // now reports address 0; one with it still gets a real address. A UI // buffer slot points at the buffer by its address, so RegisterBuffer refuses // a buffer without one rather than registering address 0. // // Needs a Vulkan device; the validation check only means something with // CRAFTER_GRAPHICS_VALIDATION set. #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; } } // namespace int main() { Device::Initialize(); Device::validationErrorCount = 0; VulkanBuffer staging; staging.Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 16); Check(staging.address == 0, std::format("a buffer without SHADER_DEVICE_ADDRESS has no address (got {:#x})", staging.address)); VulkanBuffer resized; resized.Resize(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 16); resized.Resize(VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 64); Check(resized.address == 0, "nor after growing through Resize"); VulkanBuffer addressable; addressable.Create(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 16); Check(addressable.address != 0, "a buffer with SHADER_DEVICE_ADDRESS has one"); // Refused before it touches the renderer, so an uninitialised one does. UIRenderer ui; bool refused = false; try { (void)ui.RegisterBuffer(staging); } catch (const std::invalid_argument&) { refused = true; } Check(refused, "RegisterBuffer refuses a buffer without a device address"); if (std::getenv("CRAFTER_GRAPHICS_VALIDATION") != nullptr) { Check(Device::validationErrorCount == 0, std::format("no Vulkan validation errors ({} seen)", Device::validationErrorCount)); } staging.Clear(); resized.Clear(); addressable.Clear(); std::println("{}", failures == 0 ? "all checks passed" : "check(s) failed"); return failures == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }