mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-26 21:17:40 +00:00
933 lines
60 KiB
C
933 lines
60 KiB
C
#include <vulkan/vulkan.h>
|
|
#include "vulkan_compute_spirv.h"
|
|
#include "vulkan_triangle_spirv.h"
|
|
#include "vulkan_quad_spirv.h"
|
|
|
|
_Static_assert(sizeof(VkInstanceCreateInfo) == 64, "PE64 instance info ABI");
|
|
_Static_assert(sizeof(VkApplicationInfo) == 48, "PE64 application info ABI");
|
|
_Static_assert(sizeof(VkPhysicalDeviceProperties) == 824, "PE64 properties ABI");
|
|
|
|
__declspec(dllexport) VkPhysicalDeviceProperties observed;
|
|
__declspec(dllexport) uint32_t device_count;
|
|
__declspec(dllexport) uint32_t loader_version;
|
|
__declspec(dllexport) uint32_t family_count;
|
|
__declspec(dllexport) VkQueueFamilyProperties families[16];
|
|
__declspec(dllexport) VkPhysicalDeviceMemoryProperties memory_properties;
|
|
__declspec(dllexport) VkPhysicalDeviceFeatures features;
|
|
__declspec(dllexport) uint32_t device_workflow;
|
|
__declspec(dllexport) uint32_t copy_workflow;
|
|
__declspec(dllexport) uint8_t copied[256];
|
|
__declspec(dllexport) uint32_t copy_fence_waits;
|
|
__declspec(dllexport) uint32_t compute_workflow;
|
|
__declspec(dllexport) uint32_t computed[64];
|
|
__declspec(dllexport) uint32_t image_workflow;
|
|
__declspec(dllexport) uint32_t image_readback[64];
|
|
__declspec(dllexport) uint32_t extension_workflow;
|
|
__declspec(dllexport) uint32_t instance_extension_count, instance_layer_count, device_extension_count, surface_offered, swapchain_offered;
|
|
__declspec(dllexport) VkPhysicalDeviceVulkan11Features features11;
|
|
__declspec(dllexport) VkPhysicalDeviceVulkan12Features features12;
|
|
__declspec(dllexport) VkPhysicalDeviceVulkan13Features features13;
|
|
__declspec(dllexport) VkPhysicalDeviceVulkan12Properties properties12;
|
|
__declspec(dllexport) VkPhysicalDeviceProperties properties_two;
|
|
__declspec(dllexport) VkPhysicalDeviceMemoryProperties memory_two;
|
|
__declspec(dllexport) VkFormatProperties format_one;
|
|
__declspec(dllexport) VkFormatProperties format_two;
|
|
__declspec(dllexport) VkImageFormatProperties image_format;
|
|
__declspec(dllexport) uint32_t family_two_count;
|
|
__declspec(dllexport) VkQueueFamilyProperties family_two;
|
|
__declspec(dllexport) uint32_t graphics_workflow;
|
|
__declspec(dllexport) uint32_t rendered[256];
|
|
__declspec(dllexport) uint32_t textured_workflow;
|
|
__declspec(dllexport) uint32_t textured[256];
|
|
|
|
unsigned int raven_entry(void)
|
|
{
|
|
if (vkEnumerateInstanceVersion(&loader_version) != VK_SUCCESS || loader_version < VK_API_VERSION_1_1)
|
|
return 1;
|
|
if (vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumeratePhysicalDevices") ||
|
|
vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkNotImplemented"))
|
|
return 2;
|
|
PFN_vkCreateInstance create = (PFN_vkCreateInstance)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance");
|
|
if (!create)
|
|
return 3;
|
|
VkApplicationInfo application = {VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, "Raven ABI fixture", 1, "Raven", 1, VK_API_VERSION_1_1};
|
|
const char *instance_extensions[] = {"VK_KHR_get_physical_device_properties2"};
|
|
VkInstanceCreateInfo info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, &application, 0, 0, 1, instance_extensions};
|
|
VkInstance instance = VK_NULL_HANDLE;
|
|
if (create(&info, 0, &instance) != VK_SUCCESS || !instance)
|
|
return 4;
|
|
if (vkEnumeratePhysicalDevices(instance, &device_count, 0) != VK_SUCCESS || !device_count || device_count > 16)
|
|
return 5;
|
|
VkPhysicalDevice devices[16];
|
|
uint32_t count = 0;
|
|
devices[0] = (VkPhysicalDevice)(uintptr_t)0x1234;
|
|
if (vkEnumeratePhysicalDevices(instance, &count, devices) != VK_INCOMPLETE || count ||
|
|
devices[0] != (VkPhysicalDevice)(uintptr_t)0x1234)
|
|
return 6;
|
|
count = 16;
|
|
if (vkEnumeratePhysicalDevices(instance, &count, devices) != VK_SUCCESS || count != device_count)
|
|
return 7;
|
|
PFN_vkGetPhysicalDeviceProperties properties = (PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties");
|
|
if (!properties)
|
|
return 8;
|
|
properties(devices[0], &observed);
|
|
if (!observed.deviceName[0] || !observed.apiVersion)
|
|
return 9;
|
|
VkPhysicalDevice repeated[16];
|
|
count = 16;
|
|
if (vkEnumeratePhysicalDevices(instance, &count, repeated) != VK_SUCCESS || repeated[0] != devices[0])
|
|
return 10;
|
|
vkGetPhysicalDeviceMemoryProperties(devices[0], &memory_properties);
|
|
vkGetPhysicalDeviceFeatures(devices[0], &features);
|
|
if (!memory_properties.memoryTypeCount || !memory_properties.memoryHeapCount)
|
|
return 11;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(devices[0], &family_count, 0);
|
|
if (!family_count || family_count > 16)
|
|
return 12;
|
|
{
|
|
uint32_t capacity = 1;
|
|
VkQueueFamilyProperties single[2];
|
|
single[1].queueCount = 0x7777;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(devices[0], &capacity, single);
|
|
if (capacity != 1 || single[1].queueCount != 0x7777)
|
|
return 13;
|
|
}
|
|
count = family_count;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(devices[0], &count, families);
|
|
if (count != family_count || !families[0].queueCount)
|
|
return 14;
|
|
{
|
|
float priority = 1.0f;
|
|
VkDeviceQueueCreateInfo queue = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0, 0, 1, &priority};
|
|
VkDeviceCreateInfo device_info = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 0, 0, 1, &queue, 0, 0, 0, 0, 0};
|
|
VkDevice device = VK_NULL_HANDLE;
|
|
VkQueue first = VK_NULL_HANDLE, second = VK_NULL_HANDLE;
|
|
PFN_vkGetDeviceProcAddr get_device_proc = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr");
|
|
if (!get_device_proc)
|
|
return 15;
|
|
if (vkCreateDevice(devices[0], &device_info, 0, &device) != VK_SUCCESS || !device)
|
|
return 16;
|
|
if (!get_device_proc(device, "vkGetDeviceQueue") || get_device_proc(device, "vkCreateInstance"))
|
|
return 17;
|
|
if (get_device_proc(device, "vkSetDebugUtilsObjectNameEXT") || get_device_proc(device, "vkCreateSwapchainKHR") ||
|
|
vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"))
|
|
return 17;
|
|
vkGetDeviceQueue(device, 0, 0, &first);
|
|
vkGetDeviceQueue(device, 0, 0, &second);
|
|
if (!first || first != second)
|
|
return 18;
|
|
if (vkDeviceWaitIdle(device) != VK_SUCCESS)
|
|
return 19;
|
|
{
|
|
VkBufferCreateInfo buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, 256,
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkBuffer source = VK_NULL_HANDLE, target = VK_NULL_HANDLE;
|
|
VkDeviceMemory source_memory = VK_NULL_HANDLE, target_memory = VK_NULL_HANDLE;
|
|
VkMemoryRequirements requirements;
|
|
uint32_t type = 0xffffffffu, index;
|
|
uint8_t *source_data = 0, *target_data = 0;
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
VkCommandBuffer command = VK_NULL_HANDLE;
|
|
VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, 0};
|
|
VkFence fence = VK_NULL_HANDLE;
|
|
VkBufferCopy region = {0, 0, 256};
|
|
VkQueue queue = first;
|
|
if (vkCreateBuffer(device, &buffer_info, 0, &source) != VK_SUCCESS || vkCreateBuffer(device, &buffer_info, 0, &target) != VK_SUCCESS)
|
|
return 20;
|
|
vkGetBufferMemoryRequirements(device, source, &requirements);
|
|
if (requirements.size < 256)
|
|
return 21;
|
|
for (index = 0; index < memory_properties.memoryTypeCount; ++index)
|
|
if ((requirements.memoryTypeBits & (1u << index)) && (memory_properties.memoryTypes[index].propertyFlags &
|
|
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
|
type = index;
|
|
break;
|
|
}
|
|
if (type == 0xffffffffu)
|
|
return 22;
|
|
{
|
|
VkMemoryAllocateInfo allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, requirements.size, type};
|
|
if (vkAllocateMemory(device, &allocation, 0, &source_memory) != VK_SUCCESS || vkAllocateMemory(device, &allocation, 0, &target_memory) != VK_SUCCESS)
|
|
return 23;
|
|
}
|
|
if (vkBindBufferMemory(device, source, source_memory, 0) != VK_SUCCESS || vkBindBufferMemory(device, target, target_memory, 0) != VK_SUCCESS)
|
|
return 24;
|
|
if (vkMapMemory(device, source_memory, 0, VK_WHOLE_SIZE, 0, (void **)&source_data) != VK_SUCCESS || !source_data ||
|
|
vkMapMemory(device, target_memory, 0, VK_WHOLE_SIZE, 0, (void **)&target_data) != VK_SUCCESS || !target_data)
|
|
return 25;
|
|
for (index = 0; index < 256; ++index) {
|
|
source_data[index] = (uint8_t)(index * 7 + 3);
|
|
target_data[index] = 0xee;
|
|
}
|
|
if (vkCreateCommandPool(device, &pool_info, 0, &pool) != VK_SUCCESS)
|
|
return 26;
|
|
{
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
if (vkAllocateCommandBuffers(device, &allocation, &command) != VK_SUCCESS || !command)
|
|
return 27;
|
|
if (vkBeginCommandBuffer(command, &begin) != VK_SUCCESS)
|
|
return 28;
|
|
}
|
|
vkCmdCopyBuffer(command, source, target, 1, ®ion);
|
|
if (vkEndCommandBuffer(command) != VK_SUCCESS)
|
|
return 29;
|
|
if (vkCreateFence(device, &fence_info, 0, &fence) != VK_SUCCESS)
|
|
return 30;
|
|
{
|
|
VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &command, 0, 0};
|
|
if (vkQueueSubmit(queue, 1, &submit, fence) != VK_SUCCESS)
|
|
return 31;
|
|
}
|
|
if (vkWaitForFences(device, 1, &fence, VK_TRUE, 10000000000ull) != VK_SUCCESS)
|
|
return 32;
|
|
++copy_fence_waits;
|
|
for (index = 0; index < 256; ++index)
|
|
if (target_data[index] != (uint8_t)(index * 7 + 3))
|
|
return 33;
|
|
for (index = 0; index < 256; ++index)
|
|
copied[index] = target_data[index];
|
|
if (vkResetFences(device, 1, &fence) != VK_SUCCESS)
|
|
return 34;
|
|
/* A second round trip through the same mappings: the guest changes the source, the device copies it again. */
|
|
source_data[0] = 0x5a;
|
|
{
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &command, 0, 0};
|
|
if (vkResetCommandPool(device, pool, 0) != VK_SUCCESS || vkBeginCommandBuffer(command, &begin) != VK_SUCCESS)
|
|
return 35;
|
|
vkCmdCopyBuffer(command, source, target, 1, ®ion);
|
|
if (vkEndCommandBuffer(command) != VK_SUCCESS || vkQueueSubmit(queue, 1, &submit, VK_NULL_HANDLE) != VK_SUCCESS || vkQueueWaitIdle(queue) != VK_SUCCESS)
|
|
return 36;
|
|
}
|
|
if (target_data[0] != 0x5a || target_data[1] != (uint8_t)(1 * 7 + 3))
|
|
return 37;
|
|
vkUnmapMemory(device, source_memory);
|
|
vkUnmapMemory(device, target_memory);
|
|
vkFreeCommandBuffers(device, pool, 1, &command);
|
|
vkDestroyFence(device, fence, 0);
|
|
vkDestroyCommandPool(device, pool, 0);
|
|
vkDestroyBuffer(device, source, 0);
|
|
vkDestroyBuffer(device, target, 0);
|
|
vkFreeMemory(device, source_memory, 0);
|
|
vkFreeMemory(device, target_memory, 0);
|
|
copy_workflow = 1;
|
|
}
|
|
{
|
|
/* A compute shader reads one storage buffer, scales it by a push constant and writes another. */
|
|
VkBufferCreateInfo buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkBuffer input = VK_NULL_HANDLE, output = VK_NULL_HANDLE;
|
|
VkDeviceMemory input_memory = VK_NULL_HANDLE, output_memory = VK_NULL_HANDLE;
|
|
VkMemoryRequirements requirements;
|
|
uint32_t type = 0xffffffffu, index, scale = 3;
|
|
uint32_t *input_data = 0, *output_data = 0;
|
|
VkShaderModuleCreateInfo shader_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, sizeof compute_words, compute_words};
|
|
VkShaderModule shader = VK_NULL_HANDLE;
|
|
VkDescriptorSetLayoutBinding bindings[2] = {
|
|
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, 0},
|
|
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, 0}};
|
|
VkDescriptorSetLayoutCreateInfo set_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 0, 0, 2, bindings};
|
|
VkDescriptorSetLayout set_layout = VK_NULL_HANDLE;
|
|
VkPushConstantRange range = {VK_SHADER_STAGE_COMPUTE_BIT, 0, 4};
|
|
VkPipelineLayoutCreateInfo layout_info = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, 1, &set_layout, 1, &range};
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2};
|
|
VkDescriptorPoolCreateInfo descriptor_pool_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 0, 0, 1, 1, &pool_size};
|
|
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
|
|
VkDescriptorSet set = VK_NULL_HANDLE;
|
|
VkDescriptorBufferInfo input_info, output_info;
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
VkCommandBuffer command = VK_NULL_HANDLE;
|
|
if (vkCreateBuffer(device, &buffer_info, 0, &input) != VK_SUCCESS || vkCreateBuffer(device, &buffer_info, 0, &output) != VK_SUCCESS)
|
|
return 40;
|
|
vkGetBufferMemoryRequirements(device, input, &requirements);
|
|
for (index = 0; index < memory_properties.memoryTypeCount; ++index)
|
|
if ((requirements.memoryTypeBits & (1u << index)) && (memory_properties.memoryTypes[index].propertyFlags &
|
|
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
|
type = index;
|
|
break;
|
|
}
|
|
if (type == 0xffffffffu)
|
|
return 41;
|
|
{
|
|
VkMemoryAllocateInfo allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, requirements.size, type};
|
|
if (vkAllocateMemory(device, &allocation, 0, &input_memory) != VK_SUCCESS || vkAllocateMemory(device, &allocation, 0, &output_memory) != VK_SUCCESS)
|
|
return 42;
|
|
}
|
|
if (vkBindBufferMemory(device, input, input_memory, 0) != VK_SUCCESS || vkBindBufferMemory(device, output, output_memory, 0) != VK_SUCCESS)
|
|
return 43;
|
|
if (vkMapMemory(device, input_memory, 0, VK_WHOLE_SIZE, 0, (void **)&input_data) != VK_SUCCESS ||
|
|
vkMapMemory(device, output_memory, 0, VK_WHOLE_SIZE, 0, (void **)&output_data) != VK_SUCCESS || !input_data || !output_data)
|
|
return 44;
|
|
for (index = 0; index < 64; ++index) {
|
|
input_data[index] = index + 10;
|
|
output_data[index] = 0xdeadbeefu;
|
|
}
|
|
if (vkCreateShaderModule(device, &shader_info, 0, &shader) != VK_SUCCESS || !shader)
|
|
return 45;
|
|
if (vkCreateDescriptorSetLayout(device, &set_layout_info, 0, &set_layout) != VK_SUCCESS || vkCreatePipelineLayout(device, &layout_info, 0, &layout) != VK_SUCCESS)
|
|
return 46;
|
|
{
|
|
VkComputePipelineCreateInfo pipeline_info = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 0, 0,
|
|
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_COMPUTE_BIT, shader, "main", 0}, layout, VK_NULL_HANDLE, -1};
|
|
if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, 0, &pipeline) != VK_SUCCESS || !pipeline)
|
|
return 47;
|
|
}
|
|
if (vkCreateDescriptorPool(device, &descriptor_pool_info, 0, &descriptor_pool) != VK_SUCCESS)
|
|
return 48;
|
|
{
|
|
VkDescriptorSetAllocateInfo allocation = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 0, descriptor_pool, 1, &set_layout};
|
|
if (vkAllocateDescriptorSets(device, &allocation, &set) != VK_SUCCESS || !set)
|
|
return 49;
|
|
}
|
|
input_info.buffer = input; input_info.offset = 0; input_info.range = VK_WHOLE_SIZE;
|
|
output_info.buffer = output; output_info.offset = 0; output_info.range = VK_WHOLE_SIZE;
|
|
{
|
|
VkWriteDescriptorSet writes[2] = {
|
|
{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, set, 0, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &input_info, 0},
|
|
{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, set, 1, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, &output_info, 0}};
|
|
vkUpdateDescriptorSets(device, 2, writes, 0, 0);
|
|
}
|
|
if (vkCreateCommandPool(device, &pool_info, 0, &pool) != VK_SUCCESS)
|
|
return 50;
|
|
{
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &command, 0, 0};
|
|
if (vkAllocateCommandBuffers(device, &allocation, &command) != VK_SUCCESS || vkBeginCommandBuffer(command, &begin) != VK_SUCCESS)
|
|
return 51;
|
|
vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
|
|
vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, 1, &set, 0, 0);
|
|
vkCmdPushConstants(command, layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 4, &scale);
|
|
vkCmdDispatch(command, 1, 1, 1);
|
|
if (vkEndCommandBuffer(command) != VK_SUCCESS || vkQueueSubmit(first, 1, &submit, VK_NULL_HANDLE) != VK_SUCCESS || vkQueueWaitIdle(first) != VK_SUCCESS)
|
|
return 52;
|
|
}
|
|
for (index = 0; index < 64; ++index) {
|
|
computed[index] = output_data[index];
|
|
if (output_data[index] != (index + 10) * scale + index)
|
|
return 53;
|
|
}
|
|
vkUnmapMemory(device, input_memory);
|
|
vkUnmapMemory(device, output_memory);
|
|
vkDestroyCommandPool(device, pool, 0);
|
|
vkDestroyDescriptorPool(device, descriptor_pool, 0);
|
|
vkDestroyPipeline(device, pipeline, 0);
|
|
vkDestroyPipelineLayout(device, layout, 0);
|
|
vkDestroyDescriptorSetLayout(device, set_layout, 0);
|
|
vkDestroyShaderModule(device, shader, 0);
|
|
vkDestroyBuffer(device, input, 0);
|
|
vkDestroyBuffer(device, output, 0);
|
|
vkFreeMemory(device, input_memory, 0);
|
|
vkFreeMemory(device, output_memory, 0);
|
|
compute_workflow = 1;
|
|
}
|
|
{
|
|
/* A 8x8 image on the device: upload from one buffer, barrier, read back into another, ordered by a semaphore. */
|
|
VkImageCreateInfo image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, {8, 8, 1}, 1, 1,
|
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED};
|
|
VkBufferCreateInfo buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, 256,
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkImage image = VK_NULL_HANDLE;
|
|
VkImageView view = VK_NULL_HANDLE;
|
|
VkBuffer upload = VK_NULL_HANDLE, download = VK_NULL_HANDLE;
|
|
VkDeviceMemory image_memory = VK_NULL_HANDLE, upload_memory = VK_NULL_HANDLE, download_memory = VK_NULL_HANDLE;
|
|
VkMemoryRequirements requirements, buffer_requirements;
|
|
uint32_t type = 0xffffffffu, host_type = 0xffffffffu, index, *upload_data = 0, *download_data = 0;
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
VkCommandBuffer commands[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
|
|
VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, 0, 0};
|
|
VkSemaphore semaphore = VK_NULL_HANDLE;
|
|
VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, 0};
|
|
VkFence fence = VK_NULL_HANDLE;
|
|
VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
|
VkBufferImageCopy copy = {0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {8, 8, 1}};
|
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
|
if (vkCreateImage(device, &image_info, 0, &image) != VK_SUCCESS || !image)
|
|
return 60;
|
|
vkGetImageMemoryRequirements(device, image, &requirements);
|
|
for (index = 0; index < 32 && type == 0xffffffffu; ++index)
|
|
if (requirements.memoryTypeBits & (1u << index))
|
|
type = index;
|
|
if (type == 0xffffffffu)
|
|
return 61;
|
|
if (vkCreateBuffer(device, &buffer_info, 0, &upload) != VK_SUCCESS || vkCreateBuffer(device, &buffer_info, 0, &download) != VK_SUCCESS)
|
|
return 62;
|
|
vkGetBufferMemoryRequirements(device, upload, &buffer_requirements);
|
|
for (index = 0; index < memory_properties.memoryTypeCount; ++index)
|
|
if ((buffer_requirements.memoryTypeBits & (1u << index)) && (memory_properties.memoryTypes[index].propertyFlags &
|
|
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
|
host_type = index;
|
|
break;
|
|
}
|
|
if (host_type == 0xffffffffu)
|
|
return 63;
|
|
{
|
|
VkMemoryAllocateInfo image_allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, requirements.size, type};
|
|
VkMemoryAllocateInfo host_allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, buffer_requirements.size, host_type};
|
|
if (vkAllocateMemory(device, &image_allocation, 0, &image_memory) != VK_SUCCESS || vkAllocateMemory(device, &host_allocation, 0, &upload_memory) != VK_SUCCESS ||
|
|
vkAllocateMemory(device, &host_allocation, 0, &download_memory) != VK_SUCCESS)
|
|
return 64;
|
|
}
|
|
if (vkBindImageMemory(device, image, image_memory, 0) != VK_SUCCESS || vkBindBufferMemory(device, upload, upload_memory, 0) != VK_SUCCESS ||
|
|
vkBindBufferMemory(device, download, download_memory, 0) != VK_SUCCESS)
|
|
return 65;
|
|
{
|
|
VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, 0, image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
|
|
{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, range};
|
|
if (vkCreateImageView(device, &view_info, 0, &view) != VK_SUCCESS || !view)
|
|
return 66;
|
|
}
|
|
if (vkMapMemory(device, upload_memory, 0, VK_WHOLE_SIZE, 0, (void **)&upload_data) != VK_SUCCESS ||
|
|
vkMapMemory(device, download_memory, 0, VK_WHOLE_SIZE, 0, (void **)&download_data) != VK_SUCCESS || !upload_data || !download_data)
|
|
return 67;
|
|
for (index = 0; index < 64; ++index) {
|
|
upload_data[index] = 0xff000000u | (index * 3u << 16) | (index * 2u << 8) | index;
|
|
download_data[index] = 0;
|
|
}
|
|
if (vkCreateCommandPool(device, &pool_info, 0, &pool) != VK_SUCCESS || vkCreateSemaphore(device, &semaphore_info, 0, &semaphore) != VK_SUCCESS ||
|
|
vkCreateFence(device, &fence_info, 0, &fence) != VK_SUCCESS)
|
|
return 68;
|
|
{
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
VkImageMemoryBarrier to_destination = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, range};
|
|
VkImageMemoryBarrier to_source = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, range};
|
|
VkSubmitInfo first_submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &commands[0], 1, &semaphore};
|
|
VkSubmitInfo second_submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 1, &semaphore, &wait_stage, 1, &commands[1], 0, 0};
|
|
if (vkAllocateCommandBuffers(device, &allocation, commands) != VK_SUCCESS || !commands[0] || !commands[1] || commands[0] == commands[1])
|
|
return 69;
|
|
vkBeginCommandBuffer(commands[0], &begin);
|
|
vkCmdPipelineBarrier(commands[0], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &to_destination);
|
|
vkCmdCopyBufferToImage(commands[0], upload, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©);
|
|
vkCmdPipelineBarrier(commands[0], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &to_source);
|
|
if (vkEndCommandBuffer(commands[0]) != VK_SUCCESS)
|
|
return 70;
|
|
vkBeginCommandBuffer(commands[1], &begin);
|
|
vkCmdCopyImageToBuffer(commands[1], image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, download, 1, ©);
|
|
if (vkEndCommandBuffer(commands[1]) != VK_SUCCESS)
|
|
return 71;
|
|
if (vkQueueSubmit(first, 1, &first_submit, VK_NULL_HANDLE) != VK_SUCCESS || vkQueueSubmit(first, 1, &second_submit, fence) != VK_SUCCESS)
|
|
return 72;
|
|
}
|
|
if (vkWaitForFences(device, 1, &fence, VK_TRUE, 10000000000ull) != VK_SUCCESS || vkGetFenceStatus(device, fence) != VK_SUCCESS)
|
|
return 73;
|
|
for (index = 0; index < 64; ++index) {
|
|
image_readback[index] = download_data[index];
|
|
if (download_data[index] != upload_data[index])
|
|
return 74;
|
|
}
|
|
vkUnmapMemory(device, upload_memory);
|
|
vkUnmapMemory(device, download_memory);
|
|
vkDestroyFence(device, fence, 0);
|
|
vkDestroySemaphore(device, semaphore, 0);
|
|
vkDestroyCommandPool(device, pool, 0);
|
|
vkDestroyImageView(device, view, 0);
|
|
vkDestroyImage(device, image, 0);
|
|
vkDestroyBuffer(device, upload, 0);
|
|
vkDestroyBuffer(device, download, 0);
|
|
vkFreeMemory(device, image_memory, 0);
|
|
vkFreeMemory(device, upload_memory, 0);
|
|
vkFreeMemory(device, download_memory, 0);
|
|
image_workflow = 1;
|
|
}
|
|
{
|
|
/* A 16x16 target cleared to blue with a red triangle over its upper left half, read back through a buffer. */
|
|
VkImageCreateInfo image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, {16, 16, 1}, 1, 1,
|
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
|
|
VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED};
|
|
VkBufferCreateInfo buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, 1024, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkImage image = VK_NULL_HANDLE;
|
|
VkImageView view = VK_NULL_HANDLE;
|
|
VkBuffer readback = VK_NULL_HANDLE;
|
|
VkDeviceMemory image_memory = VK_NULL_HANDLE, readback_memory = VK_NULL_HANDLE;
|
|
VkMemoryRequirements requirements, buffer_requirements;
|
|
uint32_t type = 0xffffffffu, host_type = 0xffffffffu, index, *pixels = 0;
|
|
VkShaderModuleCreateInfo vertex_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, sizeof triangle_vertex_words, triangle_vertex_words};
|
|
VkShaderModuleCreateInfo fragment_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, sizeof triangle_fragment_words, triangle_fragment_words};
|
|
VkShaderModule vertex = VK_NULL_HANDLE, fragment = VK_NULL_HANDLE;
|
|
VkAttachmentDescription attachment = {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
|
|
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL};
|
|
VkAttachmentReference reference = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
|
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, 1, &reference, 0, 0, 0, 0};
|
|
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, 1, &attachment, 1, &subpass, 0, 0};
|
|
VkRenderPass pass = VK_NULL_HANDLE;
|
|
VkFramebufferCreateInfo framebuffer_info;
|
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
|
VkPipelineLayoutCreateInfo layout_info = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, 0, 0, 0, 0};
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
VkCommandBuffer command = VK_NULL_HANDLE;
|
|
VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
|
VkBufferImageCopy copy = {0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {16, 16, 1}};
|
|
if (vkCreateImage(device, &image_info, 0, &image) != VK_SUCCESS)
|
|
return 80;
|
|
vkGetImageMemoryRequirements(device, image, &requirements);
|
|
for (index = 0; index < 32 && type == 0xffffffffu; ++index)
|
|
if (requirements.memoryTypeBits & (1u << index))
|
|
type = index;
|
|
if (vkCreateBuffer(device, &buffer_info, 0, &readback) != VK_SUCCESS)
|
|
return 81;
|
|
vkGetBufferMemoryRequirements(device, readback, &buffer_requirements);
|
|
for (index = 0; index < memory_properties.memoryTypeCount; ++index)
|
|
if ((buffer_requirements.memoryTypeBits & (1u << index)) && (memory_properties.memoryTypes[index].propertyFlags &
|
|
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) == (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
|
|
host_type = index;
|
|
break;
|
|
}
|
|
if (type == 0xffffffffu || host_type == 0xffffffffu)
|
|
return 82;
|
|
{
|
|
VkMemoryAllocateInfo image_allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, requirements.size, type};
|
|
VkMemoryAllocateInfo host_allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, buffer_requirements.size, host_type};
|
|
if (vkAllocateMemory(device, &image_allocation, 0, &image_memory) != VK_SUCCESS || vkAllocateMemory(device, &host_allocation, 0, &readback_memory) != VK_SUCCESS)
|
|
return 83;
|
|
}
|
|
if (vkBindImageMemory(device, image, image_memory, 0) != VK_SUCCESS || vkBindBufferMemory(device, readback, readback_memory, 0) != VK_SUCCESS ||
|
|
vkMapMemory(device, readback_memory, 0, VK_WHOLE_SIZE, 0, (void **)&pixels) != VK_SUCCESS || !pixels)
|
|
return 84;
|
|
for (index = 0; index < 256; ++index)
|
|
pixels[index] = 0x11223344u;
|
|
{
|
|
VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, 0, image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
|
|
{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, range};
|
|
if (vkCreateImageView(device, &view_info, 0, &view) != VK_SUCCESS)
|
|
return 85;
|
|
}
|
|
if (vkCreateShaderModule(device, &vertex_info, 0, &vertex) != VK_SUCCESS || vkCreateShaderModule(device, &fragment_info, 0, &fragment) != VK_SUCCESS)
|
|
return 86;
|
|
if (vkCreateRenderPass(device, &pass_info, 0, &pass) != VK_SUCCESS || !pass)
|
|
return 87;
|
|
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebuffer_info.pNext = 0; framebuffer_info.flags = 0;
|
|
framebuffer_info.renderPass = pass; framebuffer_info.attachmentCount = 1; framebuffer_info.pAttachments = &view;
|
|
framebuffer_info.width = 16; framebuffer_info.height = 16; framebuffer_info.layers = 1;
|
|
if (vkCreateFramebuffer(device, &framebuffer_info, 0, &framebuffer) != VK_SUCCESS || vkCreatePipelineLayout(device, &layout_info, 0, &layout) != VK_SUCCESS)
|
|
return 88;
|
|
{
|
|
VkPipelineShaderStageCreateInfo stages[2] = {
|
|
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_VERTEX_BIT, vertex, "main", 0},
|
|
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_FRAGMENT_BIT, fragment, "main", 0}};
|
|
VkPipelineVertexInputStateCreateInfo vertex_state = {VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 0, 0, 0, 0, 0, 0};
|
|
VkPipelineInputAssemblyStateCreateInfo assembly = {VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 0, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE};
|
|
VkViewport viewport = {0, 0, 16, 16, 0, 1};
|
|
VkRect2D scissor = {{0, 0}, {16, 16}};
|
|
VkPipelineViewportStateCreateInfo viewport_state = {VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 0, 0, 1, &viewport, 1, &scissor};
|
|
VkPipelineRasterizationStateCreateInfo raster = {VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 0, 0, VK_FALSE, VK_FALSE,
|
|
VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, VK_FALSE, 0, 0, 0, 1.0f};
|
|
VkPipelineMultisampleStateCreateInfo multisample = {VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 0, 0, VK_SAMPLE_COUNT_1_BIT, VK_FALSE, 0, 0, VK_FALSE, VK_FALSE};
|
|
VkPipelineColorBlendAttachmentState blend_attachment = {VK_FALSE, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
|
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
|
|
VkPipelineColorBlendStateCreateInfo blend = {VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 0, 0, VK_FALSE, VK_LOGIC_OP_COPY, 1, &blend_attachment, {0, 0, 0, 0}};
|
|
VkGraphicsPipelineCreateInfo pipeline_info = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 0, 0, 2, stages, &vertex_state, &assembly, 0, &viewport_state,
|
|
&raster, &multisample, 0, &blend, 0, layout, pass, 0, VK_NULL_HANDLE, -1};
|
|
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, 0, &pipeline) != VK_SUCCESS || !pipeline)
|
|
return 89;
|
|
}
|
|
if (vkCreateCommandPool(device, &pool_info, 0, &pool) != VK_SUCCESS)
|
|
return 90;
|
|
{
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
VkClearValue clear;
|
|
VkRenderPassBeginInfo pass_begin;
|
|
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, range};
|
|
VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &command, 0, 0};
|
|
clear.color.float32[0] = 0.0f; clear.color.float32[1] = 0.0f; clear.color.float32[2] = 1.0f; clear.color.float32[3] = 1.0f;
|
|
pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; pass_begin.pNext = 0; pass_begin.renderPass = pass; pass_begin.framebuffer = framebuffer;
|
|
pass_begin.renderArea.offset.x = 0; pass_begin.renderArea.offset.y = 0; pass_begin.renderArea.extent.width = 16; pass_begin.renderArea.extent.height = 16;
|
|
pass_begin.clearValueCount = 1; pass_begin.pClearValues = &clear;
|
|
if (vkAllocateCommandBuffers(device, &allocation, &command) != VK_SUCCESS || vkBeginCommandBuffer(command, &begin) != VK_SUCCESS)
|
|
return 91;
|
|
vkCmdBeginRenderPass(command, &pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
vkCmdDraw(command, 3, 1, 0, 0);
|
|
vkCmdEndRenderPass(command);
|
|
vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &barrier);
|
|
vkCmdCopyImageToBuffer(command, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readback, 1, ©);
|
|
if (vkEndCommandBuffer(command) != VK_SUCCESS || vkQueueSubmit(first, 1, &submit, VK_NULL_HANDLE) != VK_SUCCESS || vkQueueWaitIdle(first) != VK_SUCCESS)
|
|
return 92;
|
|
}
|
|
for (index = 0; index < 256; ++index)
|
|
rendered[index] = pixels[index];
|
|
/* Pixel (2,2) lies inside the triangle, pixel (14,14) outside it. */
|
|
if (pixels[2 * 16 + 2] != 0xff0000ffu || pixels[14 * 16 + 14] != 0xffff0000u)
|
|
return 93;
|
|
vkUnmapMemory(device, readback_memory);
|
|
vkDestroyCommandPool(device, pool, 0);
|
|
vkDestroyPipeline(device, pipeline, 0);
|
|
vkDestroyPipelineLayout(device, layout, 0);
|
|
vkDestroyFramebuffer(device, framebuffer, 0);
|
|
vkDestroyRenderPass(device, pass, 0);
|
|
vkDestroyShaderModule(device, vertex, 0);
|
|
vkDestroyShaderModule(device, fragment, 0);
|
|
vkDestroyImageView(device, view, 0);
|
|
vkDestroyImage(device, image, 0);
|
|
vkDestroyBuffer(device, readback, 0);
|
|
vkFreeMemory(device, image_memory, 0);
|
|
vkFreeMemory(device, readback_memory, 0);
|
|
graphics_workflow = 1;
|
|
}
|
|
{
|
|
/* A quad from vertex and index buffers, sampling a 2x2 texture through a combined image sampler, with dynamic viewport and scissor. */
|
|
static const float vertices[16] = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1};
|
|
static const uint16_t indices[6] = {0, 1, 2, 2, 3, 0};
|
|
static const uint32_t texels[4] = {0xff0000ffu, 0xff00ff00u, 0xffff0000u, 0xffffffffu};
|
|
VkImageCreateInfo target_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, {16, 16, 1}, 1, 1,
|
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED};
|
|
VkImageCreateInfo texture_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 0, 0, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, {2, 2, 1}, 1, 1,
|
|
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED};
|
|
VkBufferCreateInfo vertex_buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, sizeof vertices, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkBufferCreateInfo index_buffer_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, sizeof indices, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkBufferCreateInfo staging_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, sizeof texels, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkBufferCreateInfo readback_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0, 1024, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, 0};
|
|
VkImage target = VK_NULL_HANDLE, texture = VK_NULL_HANDLE;
|
|
VkImageView target_view = VK_NULL_HANDLE, texture_view = VK_NULL_HANDLE;
|
|
VkBuffer vertex_buffer = VK_NULL_HANDLE, index_buffer = VK_NULL_HANDLE, staging = VK_NULL_HANDLE, readback = VK_NULL_HANDLE;
|
|
VkDeviceMemory target_memory = VK_NULL_HANDLE, texture_memory = VK_NULL_HANDLE, vertex_memory = VK_NULL_HANDLE, index_memory = VK_NULL_HANDLE,
|
|
staging_memory = VK_NULL_HANDLE, readback_memory = VK_NULL_HANDLE;
|
|
VkMemoryRequirements requirements;
|
|
uint32_t host_type = 0xffffffffu, index, type, *pixels = 0;
|
|
void *mapped = 0;
|
|
VkSamplerCreateInfo sampler_info = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 0, 0, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, VK_FALSE, 1, VK_FALSE,
|
|
VK_COMPARE_OP_ALWAYS, 0, 0, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, VK_FALSE};
|
|
VkSampler sampler = VK_NULL_HANDLE;
|
|
VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
|
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, 0};
|
|
VkDescriptorSetLayoutCreateInfo set_layout_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 0, 0, 1, &binding};
|
|
VkDescriptorSetLayout set_layout = VK_NULL_HANDLE;
|
|
VkPipelineLayoutCreateInfo layout_info = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 0, 0, 1, &set_layout, 0, 0};
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1};
|
|
VkDescriptorPoolCreateInfo descriptor_pool_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 0, 0, 1, 1, &pool_size};
|
|
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
|
|
VkDescriptorSet set = VK_NULL_HANDLE;
|
|
VkShaderModuleCreateInfo vertex_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, sizeof quad_vertex_words, quad_vertex_words};
|
|
VkShaderModuleCreateInfo fragment_info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 0, 0, sizeof quad_fragment_words, quad_fragment_words};
|
|
VkShaderModule vertex = VK_NULL_HANDLE, fragment = VK_NULL_HANDLE;
|
|
VkAttachmentDescription attachment = {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
|
|
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL};
|
|
VkAttachmentReference reference = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
|
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, 1, &reference, 0, 0, 0, 0};
|
|
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 0, 0, 1, &attachment, 1, &subpass, 0, 0};
|
|
VkRenderPass pass = VK_NULL_HANDLE;
|
|
VkFramebufferCreateInfo framebuffer_info;
|
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
VkCommandBuffer command = VK_NULL_HANDLE;
|
|
VkBufferImageCopy upload = {0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {2, 2, 1}};
|
|
VkBufferImageCopy download = {0, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, {0, 0, 0}, {16, 16, 1}};
|
|
VkDescriptorImageInfo image_info;
|
|
/* One helper pattern for every buffer and image: find a memory type, allocate, bind. */
|
|
#define RAVEN_BUFFER(buffer, memory, info, flags) \
|
|
do { VkMemoryRequirements need; uint32_t pick = 0xffffffffu, at; \
|
|
if (vkCreateBuffer(device, &(info), 0, &(buffer)) != VK_SUCCESS) return 100; \
|
|
vkGetBufferMemoryRequirements(device, buffer, &need); \
|
|
for (at = 0; at < memory_properties.memoryTypeCount && pick == 0xffffffffu; ++at) \
|
|
if ((need.memoryTypeBits & (1u << at)) && (memory_properties.memoryTypes[at].propertyFlags & (flags)) == (flags)) pick = at; \
|
|
if (pick == 0xffffffffu) return 101; \
|
|
{ VkMemoryAllocateInfo allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, need.size, pick}; \
|
|
if (vkAllocateMemory(device, &allocation, 0, &(memory)) != VK_SUCCESS || vkBindBufferMemory(device, buffer, memory, 0) != VK_SUCCESS) return 102; } } while (0)
|
|
{
|
|
const uint32_t host_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
RAVEN_BUFFER(vertex_buffer, vertex_memory, vertex_buffer_info, host_flags);
|
|
RAVEN_BUFFER(index_buffer, index_memory, index_buffer_info, host_flags);
|
|
RAVEN_BUFFER(staging, staging_memory, staging_info, host_flags);
|
|
RAVEN_BUFFER(readback, readback_memory, readback_info, host_flags);
|
|
}
|
|
(void)host_type;
|
|
if (vkMapMemory(device, vertex_memory, 0, VK_WHOLE_SIZE, 0, &mapped) != VK_SUCCESS)
|
|
return 103;
|
|
for (index = 0; index < 16; ++index)
|
|
((float *)mapped)[index] = vertices[index];
|
|
vkUnmapMemory(device, vertex_memory);
|
|
if (vkMapMemory(device, index_memory, 0, VK_WHOLE_SIZE, 0, &mapped) != VK_SUCCESS)
|
|
return 104;
|
|
for (index = 0; index < 6; ++index)
|
|
((uint16_t *)mapped)[index] = indices[index];
|
|
vkUnmapMemory(device, index_memory);
|
|
if (vkMapMemory(device, staging_memory, 0, VK_WHOLE_SIZE, 0, &mapped) != VK_SUCCESS)
|
|
return 105;
|
|
for (index = 0; index < 4; ++index)
|
|
((uint32_t *)mapped)[index] = texels[index];
|
|
vkUnmapMemory(device, staging_memory);
|
|
if (vkMapMemory(device, readback_memory, 0, VK_WHOLE_SIZE, 0, (void **)&pixels) != VK_SUCCESS)
|
|
return 106;
|
|
for (index = 0; index < 256; ++index)
|
|
pixels[index] = 0x11223344u;
|
|
if (vkCreateImage(device, &target_info, 0, &target) != VK_SUCCESS || vkCreateImage(device, &texture_info, 0, &texture) != VK_SUCCESS)
|
|
return 107;
|
|
#define RAVEN_IMAGE(image, memory) \
|
|
do { uint32_t pick = 0xffffffffu, at; vkGetImageMemoryRequirements(device, image, &requirements); \
|
|
for (at = 0; at < 32 && pick == 0xffffffffu; ++at) if (requirements.memoryTypeBits & (1u << at)) pick = at; \
|
|
{ VkMemoryAllocateInfo allocation = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 0, requirements.size, pick}; \
|
|
if (pick == 0xffffffffu || vkAllocateMemory(device, &allocation, 0, &(memory)) != VK_SUCCESS || vkBindImageMemory(device, image, memory, 0) != VK_SUCCESS) return 108; } } while (0)
|
|
RAVEN_IMAGE(target, target_memory);
|
|
RAVEN_IMAGE(texture, texture_memory);
|
|
(void)type;
|
|
{
|
|
VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 0, 0, target, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM,
|
|
{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, range};
|
|
if (vkCreateImageView(device, &view_info, 0, &target_view) != VK_SUCCESS)
|
|
return 109;
|
|
view_info.image = texture;
|
|
if (vkCreateImageView(device, &view_info, 0, &texture_view) != VK_SUCCESS)
|
|
return 110;
|
|
}
|
|
if (vkCreateSampler(device, &sampler_info, 0, &sampler) != VK_SUCCESS || !sampler)
|
|
return 111;
|
|
if (vkCreateDescriptorSetLayout(device, &set_layout_info, 0, &set_layout) != VK_SUCCESS || vkCreatePipelineLayout(device, &layout_info, 0, &layout) != VK_SUCCESS ||
|
|
vkCreateDescriptorPool(device, &descriptor_pool_info, 0, &descriptor_pool) != VK_SUCCESS)
|
|
return 112;
|
|
{
|
|
VkDescriptorSetAllocateInfo allocation = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 0, descriptor_pool, 1, &set_layout};
|
|
VkWriteDescriptorSet write = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &image_info, 0, 0};
|
|
if (vkAllocateDescriptorSets(device, &allocation, &set) != VK_SUCCESS)
|
|
return 113;
|
|
image_info.sampler = sampler; image_info.imageView = texture_view; image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
write.dstSet = set;
|
|
vkUpdateDescriptorSets(device, 1, &write, 0, 0);
|
|
}
|
|
if (vkCreateShaderModule(device, &vertex_info, 0, &vertex) != VK_SUCCESS || vkCreateShaderModule(device, &fragment_info, 0, &fragment) != VK_SUCCESS ||
|
|
vkCreateRenderPass(device, &pass_info, 0, &pass) != VK_SUCCESS)
|
|
return 114;
|
|
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebuffer_info.pNext = 0; framebuffer_info.flags = 0;
|
|
framebuffer_info.renderPass = pass; framebuffer_info.attachmentCount = 1; framebuffer_info.pAttachments = &target_view;
|
|
framebuffer_info.width = 16; framebuffer_info.height = 16; framebuffer_info.layers = 1;
|
|
if (vkCreateFramebuffer(device, &framebuffer_info, 0, &framebuffer) != VK_SUCCESS)
|
|
return 115;
|
|
{
|
|
VkPipelineShaderStageCreateInfo stages[2] = {
|
|
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_VERTEX_BIT, vertex, "main", 0},
|
|
{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 0, 0, VK_SHADER_STAGE_FRAGMENT_BIT, fragment, "main", 0}};
|
|
VkVertexInputBindingDescription vertex_binding = {0, 16, VK_VERTEX_INPUT_RATE_VERTEX};
|
|
VkVertexInputAttributeDescription attributes[2] = {{0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, {1, 0, VK_FORMAT_R32G32_SFLOAT, 8}};
|
|
VkPipelineVertexInputStateCreateInfo vertex_state = {VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 0, 0, 1, &vertex_binding, 2, attributes};
|
|
VkPipelineInputAssemblyStateCreateInfo assembly = {VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 0, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE};
|
|
VkPipelineViewportStateCreateInfo viewport_state = {VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 0, 0, 1, 0, 1, 0};
|
|
VkPipelineRasterizationStateCreateInfo raster = {VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 0, 0, VK_FALSE, VK_FALSE,
|
|
VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE, VK_FALSE, 0, 0, 0, 1.0f};
|
|
VkPipelineMultisampleStateCreateInfo multisample = {VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 0, 0, VK_SAMPLE_COUNT_1_BIT, VK_FALSE, 0, 0, VK_FALSE, VK_FALSE};
|
|
VkPipelineColorBlendAttachmentState blend_attachment = {VK_FALSE, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
|
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
|
|
VkPipelineColorBlendStateCreateInfo blend = {VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 0, 0, VK_FALSE, VK_LOGIC_OP_COPY, 1, &blend_attachment, {0, 0, 0, 0}};
|
|
VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
|
VkPipelineDynamicStateCreateInfo dynamic = {VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, 0, 0, 2, dynamic_states};
|
|
VkGraphicsPipelineCreateInfo pipeline_info = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 0, 0, 2, stages, &vertex_state, &assembly, 0, &viewport_state,
|
|
&raster, &multisample, 0, &blend, &dynamic, layout, pass, 0, VK_NULL_HANDLE, -1};
|
|
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, 0, &pipeline) != VK_SUCCESS || !pipeline)
|
|
return 116;
|
|
}
|
|
if (vkCreateCommandPool(device, &pool_info, 0, &pool) != VK_SUCCESS)
|
|
return 117;
|
|
{
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 0};
|
|
VkImageMemoryBarrier to_destination = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, texture, range};
|
|
VkImageMemoryBarrier to_shader = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, texture, range};
|
|
VkImageMemoryBarrier to_copy = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, target, range};
|
|
VkClearValue clear;
|
|
VkRenderPassBeginInfo pass_begin;
|
|
VkBuffer vertex_buffers[1];
|
|
VkDeviceSize offsets[1] = {0};
|
|
VkViewport viewport = {0, 0, 16, 16, 0, 1};
|
|
VkRect2D scissor = {{0, 0}, {16, 16}};
|
|
VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO, 0, 0, 0, 0, 1, &command, 0, 0};
|
|
vertex_buffers[0] = vertex_buffer;
|
|
clear.color.float32[0] = 0.0f; clear.color.float32[1] = 0.0f; clear.color.float32[2] = 0.0f; clear.color.float32[3] = 1.0f;
|
|
pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; pass_begin.pNext = 0; pass_begin.renderPass = pass; pass_begin.framebuffer = framebuffer;
|
|
pass_begin.renderArea.offset.x = 0; pass_begin.renderArea.offset.y = 0; pass_begin.renderArea.extent.width = 16; pass_begin.renderArea.extent.height = 16;
|
|
pass_begin.clearValueCount = 1; pass_begin.pClearValues = &clear;
|
|
if (vkAllocateCommandBuffers(device, &allocation, &command) != VK_SUCCESS || vkBeginCommandBuffer(command, &begin) != VK_SUCCESS)
|
|
return 118;
|
|
vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &to_destination);
|
|
vkCmdCopyBufferToImage(command, staging, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &upload);
|
|
vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, 0, 0, 0, 1, &to_shader);
|
|
vkCmdBeginRenderPass(command, &pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
|
vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
|
vkCmdSetViewport(command, 0, 1, &viewport);
|
|
vkCmdSetScissor(command, 0, 1, &scissor);
|
|
vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, 1, &set, 0, 0);
|
|
vkCmdBindVertexBuffers(command, 0, 1, vertex_buffers, offsets);
|
|
vkCmdBindIndexBuffer(command, index_buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
vkCmdDrawIndexed(command, 6, 1, 0, 0, 0);
|
|
vkCmdEndRenderPass(command);
|
|
vkCmdPipelineBarrier(command, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, 0, 0, 0, 1, &to_copy);
|
|
vkCmdCopyImageToBuffer(command, target, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readback, 1, &download);
|
|
if (vkEndCommandBuffer(command) != VK_SUCCESS || vkQueueSubmit(first, 1, &submit, VK_NULL_HANDLE) != VK_SUCCESS || vkQueueWaitIdle(first) != VK_SUCCESS)
|
|
return 119;
|
|
}
|
|
for (index = 0; index < 256; ++index)
|
|
textured[index] = pixels[index];
|
|
if (pixels[4 * 16 + 4] != 0xff0000ffu || pixels[4 * 16 + 12] != 0xff00ff00u || pixels[12 * 16 + 4] != 0xffff0000u || pixels[12 * 16 + 12] != 0xffffffffu)
|
|
return 120;
|
|
vkUnmapMemory(device, readback_memory);
|
|
vkDestroyCommandPool(device, pool, 0);
|
|
vkDestroyPipeline(device, pipeline, 0);
|
|
vkDestroyFramebuffer(device, framebuffer, 0);
|
|
vkDestroyRenderPass(device, pass, 0);
|
|
vkDestroyShaderModule(device, vertex, 0);
|
|
vkDestroyShaderModule(device, fragment, 0);
|
|
vkDestroyDescriptorPool(device, descriptor_pool, 0);
|
|
vkDestroyPipelineLayout(device, layout, 0);
|
|
vkDestroyDescriptorSetLayout(device, set_layout, 0);
|
|
vkDestroySampler(device, sampler, 0);
|
|
vkDestroyImageView(device, texture_view, 0);
|
|
vkDestroyImageView(device, target_view, 0);
|
|
vkDestroyImage(device, texture, 0);
|
|
vkDestroyImage(device, target, 0);
|
|
vkDestroyBuffer(device, vertex_buffer, 0);
|
|
vkDestroyBuffer(device, index_buffer, 0);
|
|
vkDestroyBuffer(device, staging, 0);
|
|
vkDestroyBuffer(device, readback, 0);
|
|
vkFreeMemory(device, target_memory, 0);
|
|
vkFreeMemory(device, texture_memory, 0);
|
|
vkFreeMemory(device, vertex_memory, 0);
|
|
vkFreeMemory(device, index_memory, 0);
|
|
vkFreeMemory(device, staging_memory, 0);
|
|
vkFreeMemory(device, readback_memory, 0);
|
|
textured_workflow = 1;
|
|
}
|
|
vkDestroyDevice(device, 0);
|
|
vkDestroyDevice(VK_NULL_HANDLE, 0);
|
|
{
|
|
VkDevice pair[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
|
|
VkCommandPool pools[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
|
|
VkCommandBuffer commands[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE};
|
|
VkCommandPoolCreateInfo pool_info = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0, 0, 0};
|
|
VkCommandBufferBeginInfo begin = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0, 0, 0};
|
|
for (uint32_t index = 0; index < 2; ++index) {
|
|
VkCommandBufferAllocateInfo allocation = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0, VK_NULL_HANDLE, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
|
|
if (vkCreateDevice(devices[0], &device_info, 0, &pair[index]) != VK_SUCCESS ||
|
|
vkCreateCommandPool(pair[index], &pool_info, 0, &pools[index]) != VK_SUCCESS)
|
|
return 70;
|
|
allocation.commandPool = pools[index];
|
|
if (vkAllocateCommandBuffers(pair[index], &allocation, &commands[index]) != VK_SUCCESS)
|
|
return 71;
|
|
}
|
|
// Alternate live devices after destroying the first one, including hosts that reuse its handle.
|
|
for (uint32_t round = 0; round < 8; ++round)
|
|
for (uint32_t index = 0; index < 2; ++index)
|
|
if (vkBeginCommandBuffer(commands[index], &begin) != VK_SUCCESS ||
|
|
vkEndCommandBuffer(commands[index]) != VK_SUCCESS || vkResetCommandPool(pair[index], pools[index], 0) != VK_SUCCESS)
|
|
return 72;
|
|
for (uint32_t index = 0; index < 2; ++index) {
|
|
vkDestroyCommandPool(pair[index], pools[index], 0);
|
|
vkDestroyDevice(pair[index], 0);
|
|
}
|
|
}
|
|
device_workflow = 1;
|
|
}
|
|
{
|
|
/* Extension and layer enumeration, chained feature and property queries, and an instance created with an offered extension. */
|
|
VkExtensionProperties extensions[64];
|
|
VkLayerProperties layers[4];
|
|
uint32_t total = 0, capacity = 64, layer_total = 0, index;
|
|
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &features11};
|
|
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &properties12};
|
|
VkPhysicalDeviceMemoryProperties2 memory2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, 0};
|
|
VkFormatProperties2 format2 = {VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 0};
|
|
VkQueueFamilyProperties2 family2 = {VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, 0};
|
|
PFN_vkGetPhysicalDeviceFeatures2KHR get_features = (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR");
|
|
PFN_vkGetPhysicalDeviceProperties2KHR get_properties = (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR");
|
|
PFN_vkGetPhysicalDeviceMemoryProperties2KHR get_memory = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties2KHR");
|
|
PFN_vkGetPhysicalDeviceFormatProperties2KHR get_format = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties2KHR");
|
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR get_families = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
|
|
if (!get_features || !get_properties || !get_memory || !get_format || !get_families)
|
|
return 138;
|
|
const char *wanted[2] = {"VK_KHR_surface", "VK_KHR_win32_surface"};
|
|
VkInstanceCreateInfo with_extensions = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, &application, 0, 0, 0, 0};
|
|
VkInstance second = VK_NULL_HANDLE;
|
|
features11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; features11.pNext = &features12;
|
|
features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; features12.pNext = &features13;
|
|
features13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; features13.pNext = 0;
|
|
properties12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; properties12.pNext = 0;
|
|
if (vkEnumerateInstanceExtensionProperties(0, &total, 0) != VK_SUCCESS || total > 64)
|
|
return 130;
|
|
instance_extension_count = total;
|
|
if (total && vkEnumerateInstanceExtensionProperties(0, &capacity, extensions) != VK_SUCCESS && capacity < total)
|
|
return 131;
|
|
capacity = 0;
|
|
if (total && vkEnumerateInstanceExtensionProperties(0, &capacity, extensions) != VK_SUCCESS && total)
|
|
; /* A zero capacity with an array reports an incomplete result, which is fine. */
|
|
for (index = 0; index < total; ++index) {
|
|
const char *name = extensions[index].extensionName;
|
|
if (name[0] == 'V' && name[3] == 'K' && name[7] == 's' && name[8] == 'u' && name[9] == 'r' && name[10] == 'f' && name[11] == 'a' && name[12] == 'c' && name[13] == 'e' && !name[14])
|
|
surface_offered = 1;
|
|
}
|
|
if (vkEnumerateInstanceLayerProperties(&layer_total, 0) != VK_SUCCESS)
|
|
return 132;
|
|
instance_layer_count = layer_total;
|
|
(void)layers;
|
|
if (surface_offered) {
|
|
with_extensions.enabledExtensionCount = 2;
|
|
with_extensions.ppEnabledExtensionNames = wanted;
|
|
if (vkCreateInstance(&with_extensions, 0, &second) != VK_SUCCESS || !second)
|
|
return 133;
|
|
vkDestroyInstance(second, 0);
|
|
}
|
|
{
|
|
VkExtensionProperties device_extensions[128];
|
|
uint32_t device_total = 0, device_capacity = 128;
|
|
if (vkEnumerateDeviceExtensionProperties(devices[0], 0, &device_total, 0) != VK_SUCCESS || device_total > 128)
|
|
return 134;
|
|
device_extension_count = device_total;
|
|
if (device_total && vkEnumerateDeviceExtensionProperties(devices[0], 0, &device_capacity, device_extensions) != VK_SUCCESS)
|
|
return 135;
|
|
for (index = 0; index < device_total; ++index)
|
|
if (device_extensions[index].extensionName[3] == 'K' && device_extensions[index].extensionName[7] == 's' && device_extensions[index].extensionName[8] == 'w')
|
|
swapchain_offered = 1;
|
|
}
|
|
get_features(devices[0], &features2);
|
|
get_properties(devices[0], &properties2);
|
|
properties_two = properties2.properties;
|
|
if (properties_two.vendorID != observed.vendorID || properties_two.deviceID != observed.deviceID ||
|
|
properties_two.limits.maxImageDimension2D != observed.limits.maxImageDimension2D)
|
|
return 139;
|
|
get_memory(devices[0], &memory2);
|
|
memory_two = memory2.memoryProperties;
|
|
if (memory_two.memoryTypeCount != memory_properties.memoryTypeCount || memory_two.memoryHeapCount != memory_properties.memoryHeapCount)
|
|
return 140;
|
|
for (index = 0; index < memory_two.memoryTypeCount; ++index)
|
|
if (memory_two.memoryTypes[index].propertyFlags != memory_properties.memoryTypes[index].propertyFlags ||
|
|
memory_two.memoryTypes[index].heapIndex != memory_properties.memoryTypes[index].heapIndex)
|
|
return 141;
|
|
for (index = 0; index < memory_two.memoryHeapCount; ++index)
|
|
if (memory_two.memoryHeaps[index].size != memory_properties.memoryHeaps[index].size ||
|
|
memory_two.memoryHeaps[index].flags != memory_properties.memoryHeaps[index].flags)
|
|
return 142;
|
|
vkGetPhysicalDeviceFormatProperties(devices[0], VK_FORMAT_R8G8B8A8_UNORM, &format_one);
|
|
get_format(devices[0], VK_FORMAT_R8G8B8A8_UNORM, &format2);
|
|
format_two = format2.formatProperties;
|
|
if (vkGetPhysicalDeviceImageFormatProperties(devices[0], VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0, &image_format) != VK_SUCCESS)
|
|
return 136;
|
|
family_two_count = 1;
|
|
get_families(devices[0], &family_two_count, &family2);
|
|
family_two = family2.queueFamilyProperties;
|
|
if (family_two_count != 1 || !family_two.queueCount || !properties_two.apiVersion)
|
|
return 137;
|
|
if (family_two.queueFlags != families[0].queueFlags || family_two.queueCount != families[0].queueCount)
|
|
return 143;
|
|
extension_workflow = 1;
|
|
}
|
|
vkDestroyInstance(instance, 0);
|
|
vkDestroyInstance(VK_NULL_HANDLE, 0);
|
|
return 0;
|
|
}
|