#include "BdaShader.hpp" #include "ColorTransferTests.hpp" #include #include "prx/libSceAgcDriver/Execution/include/BdaFeatures.hpp" #include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp" #include "prx/libSceAgcDriver/Graphics/include/Resources.hpp" #include #include #include #include namespace AgcDriver::Graphics { Recorder* Recorder::Active() { return nullptr; } void Recorder::Submit() { Require(false, "the device tests have no recorder"); } bool Recorder::Reap() { Require(false, "the device tests have no recorder"); return false; } } namespace { using namespace AgcDriver::Graphics; class Device { public: Device() { #ifdef _WIN32 library = SDL_LoadObject("vulkan-1.dll"); #else library = SDL_LoadObject("libvulkan.so.1"); #endif Require(library != nullptr, "cannot load Vulkan"); try { instanceProc = reinterpret_cast(SDL_LoadFunction(library, "vkGetInstanceProcAddr")); Require(instanceProc != nullptr, "missing Vulkan instance resolver"); VkApplicationInfo application{VK_STRUCTURE_TYPE_APPLICATION_INFO}; application.apiVersion = VK_API_VERSION_1_1; VkInstanceCreateInfo info{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; info.pApplicationInfo = &application; Check(function("vkCreateInstance")(&info, nullptr, &instance), "vkCreateInstance"); std::uint32_t count = 0; const auto enumerate = function("vkEnumeratePhysicalDevices"); Check(enumerate(instance, &count, nullptr), "vkEnumeratePhysicalDevices"); Require(count != 0, "no Vulkan device"); std::vector devices(count); Check(enumerate(instance, &count, devices.data()), "vkEnumeratePhysicalDevices"); context.physical = devices.front(); const auto extensions = function("vkEnumerateDeviceExtensionProperties"); Check(extensions(context.physical, nullptr, &count, nullptr), "vkEnumerateDeviceExtensionProperties"); std::vector available(count); Check(extensions(context.physical, nullptr, &count, available.data()), "vkEnumerateDeviceExtensionProperties"); auto bytes = AgcDriver::QueryBdaByteFeatures(context.physical, function("vkGetPhysicalDeviceFeatures2"), available); auto address = AgcDriver::QueryBdaFeatures(context.physical, function("vkGetPhysicalDeviceFeatures2"), available); const auto queues = function("vkGetPhysicalDeviceQueueFamilyProperties"); queues(context.physical, &count, nullptr); std::vector families(count); queues(context.physical, &count, families.data()); std::uint32_t family = 0; while (family < count && (families[family].queueFlags & VK_QUEUE_COMPUTE_BIT) == 0) ++family; Require(family < count, "no Vulkan compute queue"); const float priority = 1; VkDeviceQueueCreateInfo queue{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}; queue.queueFamilyIndex = family; queue.queueCount = 1; queue.pQueuePriorities = &priority; VkPhysicalDeviceFeatures enabled{}; enabled.shaderInt64 = VK_TRUE; address.pNext = &bytes; const std::array extensionsEnabled{VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME}; VkDeviceCreateInfo device{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, &address}; device.queueCreateInfoCount = 1; device.pQueueCreateInfos = &queue; device.enabledExtensionCount = 2; device.ppEnabledExtensionNames = extensionsEnabled.data(); device.pEnabledFeatures = &enabled; Check(function("vkCreateDevice")(context.physical, &device, nullptr, &context.device), "vkCreateDevice"); context.deviceProc = function("vkGetDeviceProcAddr"); function("vkGetPhysicalDeviceMemoryProperties")(context.physical, &context.memory); VkPhysicalDeviceProperties properties{}; function("vkGetPhysicalDeviceProperties")(context.physical, &properties); context.limits = properties.limits; context.bufferDeviceAddress = true; context.Function("vkGetDeviceQueue")(context.device, family, 0, &context.queue); VkCommandPoolCreateInfo pool{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; pool.queueFamilyIndex = family; Check(context.Function("vkCreateCommandPool")(context.device, &pool, nullptr, &context.pool), "vkCreateCommandPool"); } catch (...) { release(); throw; } } ~Device() { release(); } const Context& GetContext() const { return context; } private: template TFunction function(const char* name) const { const auto result = reinterpret_cast(instanceProc(instance, name)); Require(result != nullptr, name); return result; } void release() noexcept { if (context.pool != VK_NULL_HANDLE) context.Function("vkDestroyCommandPool")(context.device, context.pool, nullptr); context.bufferPool.reset(); if (context.device != VK_NULL_HANDLE) function("vkDestroyDevice")(context.device, nullptr); if (instance != VK_NULL_HANDLE) function("vkDestroyInstance")(instance, nullptr); if (library != nullptr) SDL_UnloadObject(library); } void* library = nullptr; PFN_vkGetInstanceProcAddr instanceProc = nullptr; VkInstance instance = VK_NULL_HANDLE; Context context{}; }; } int main(int argc, char** argv) { try { RunBdaContractTests(); if (argc == 2) { const auto shader = MakeBdaTestShader(0x7fff12340000ULL, 32); std::ofstream file(argv[1], std::ios::binary); file.write(reinterpret_cast(shader.data()), static_cast(shader.size() * sizeof(std::uint32_t))); Require(static_cast(file), "cannot save BDA test SPIR-V"); return 0; } Device device; Buffer buffer(device.GetContext(), 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); Require(buffer.DeviceAddress() != 0 && buffer.Bytes().size() == 256, "invalid real BDA buffer"); buffer.Bytes()[255] = std::byte{0x5a}; Require(buffer.Bytes()[255] == std::byte{0x5a}, "real BDA buffer mapping failed"); RunBdaExecutionTests(device.GetContext()); RunColorTransferTests(device.GetContext()); std::cout << "Vulkan BDA allocation and execution tests passed\n"; return 0; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; return 1; } }