From 58703de05c2f86cc19c2b76b040e412c532c3664 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen <maister@archlinux.us> Date: Sun, 26 Jun 2016 20:58:28 +0200 Subject: [PATCH] Vulkan: Add initial async compute. Still not really async. Need to use multiple queues. --- .../Makefile | 62 ++ .../libretro-test.c | 618 ++++++++++++++++++ .../libretro-test-vulkan-async-compute/link.T | 5 + .../shaders/Makefile | 15 + .../shaders/raymarch.comp | 18 + .../shaders/raymarch.comp.inc | 117 ++++ 6 files changed, 835 insertions(+) create mode 100644 cores/libretro-test-vulkan-async-compute/Makefile create mode 100644 cores/libretro-test-vulkan-async-compute/libretro-test.c create mode 100644 cores/libretro-test-vulkan-async-compute/link.T create mode 100644 cores/libretro-test-vulkan-async-compute/shaders/Makefile create mode 100644 cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp create mode 100644 cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp.inc diff --git a/cores/libretro-test-vulkan-async-compute/Makefile b/cores/libretro-test-vulkan-async-compute/Makefile new file mode 100644 index 0000000000..e13f4560c4 --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/Makefile @@ -0,0 +1,62 @@ +ifeq ($(platform),) + platform = unix + ifeq ($(shell uname -a),) + platform = win + else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win + else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx + arch = intel + ifeq ($(shell uname -p),powerpc) + arch = ppc + endif + else ifneq ($(findstring win,$(shell uname -a)),) + platform = win + endif +endif + +# system platform +system_platform = unix +ifeq ($(shell uname -a),) + EXE_EXT = .exe + system_platform = win +else ifneq ($(findstring MINGW,$(shell uname -a)),) + system_platform = win +endif + +TARGET_NAME = testvulkan_async_compute + +ifeq ($(platform), unix) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T -Wl,--no-undefined +else + CC = gcc + TARGET := $(TARGET_NAME)_libretro.dll + SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined + CFLAGS += -I.. +endif + +ifeq ($(DEBUG), 1) + CFLAGS += -O0 -g +else + CFLAGS += -O3 +endif + +CFLAGS += -std=gnu99 +OBJECTS := libretro-test.o ../../libretro-common/vulkan/vulkan_symbol_wrapper.o +CFLAGS += -Wall -pedantic $(fpic) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) $(LIBS) -lm + +%.o: %.c + $(CC) -I../../libretro-common/include $(CFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJECTS) $(TARGET) + +.PHONY: clean + diff --git a/cores/libretro-test-vulkan-async-compute/libretro-test.c b/cores/libretro-test-vulkan-async-compute/libretro-test.c new file mode 100644 index 0000000000..a09a35049a --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/libretro-test.c @@ -0,0 +1,618 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "vulkan/vulkan_symbol_wrapper.h" +#include <libretro_vulkan.h> + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +static struct retro_hw_render_callback hw_render; +static const struct retro_hw_render_interface_vulkan *vulkan; +static unsigned frame_count; + +#define BASE_WIDTH 640 +#define BASE_HEIGHT 360 +#define MAX_SYNC 8 + +struct buffer +{ + VkBuffer buffer; + VkDeviceMemory memory; +}; + +struct vulkan_data +{ + unsigned index; + unsigned num_swapchain_images; + uint32_t swapchain_mask; + + VkPhysicalDeviceMemoryProperties memory_properties; + VkPhysicalDeviceProperties gpu_properties; + + VkDescriptorSetLayout set_layout; + VkDescriptorPool desc_pool; + VkDescriptorSet desc_set[MAX_SYNC]; + + VkPipelineCache pipeline_cache; + VkPipelineLayout pipeline_layout; + VkPipeline pipeline; + + struct retro_vulkan_image images[MAX_SYNC]; + VkDeviceMemory image_memory[MAX_SYNC]; + VkCommandPool cmd_pool[MAX_SYNC]; + VkCommandBuffer cmd[MAX_SYNC]; + VkSemaphore acquire_semaphores[MAX_SYNC]; +}; +static struct vulkan_data vk; + +void retro_init(void) +{} + +void retro_deinit(void) +{} + +unsigned retro_api_version(void) +{ + return RETRO_API_VERSION; +} + +void retro_set_controller_port_device(unsigned port, unsigned device) +{ + (void)port; + (void)device; +} + +void retro_get_system_info(struct retro_system_info *info) +{ + memset(info, 0, sizeof(*info)); + info->library_name = "TestCore Async Compute Vulkan"; + info->library_version = "v1"; + info->need_fullpath = false; + info->valid_extensions = NULL; // Anything is fine, we don't care. +} + +void retro_get_system_av_info(struct retro_system_av_info *info) +{ + info->timing = (struct retro_system_timing) { + .fps = 60.0, + .sample_rate = 30000.0, + }; + + info->geometry = (struct retro_game_geometry) { + .base_width = BASE_WIDTH, + .base_height = BASE_HEIGHT, + .max_width = BASE_WIDTH, + .max_height = BASE_HEIGHT, + .aspect_ratio = (float)BASE_WIDTH / (float)BASE_HEIGHT, + }; +} + +static retro_video_refresh_t video_cb; +static retro_audio_sample_t audio_cb; +static retro_audio_sample_batch_t audio_batch_cb; +static retro_environment_t environ_cb; +static retro_input_poll_t input_poll_cb; +static retro_input_state_t input_state_cb; + +void retro_set_environment(retro_environment_t cb) +{ + environ_cb = cb; + + bool no_rom = true; + cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom); +} + +void retro_set_audio_sample(retro_audio_sample_t cb) +{ + audio_cb = cb; +} + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + audio_batch_cb = cb; +} + +void retro_set_input_poll(retro_input_poll_t cb) +{ + input_poll_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) +{ + input_state_cb = cb; +} + +void retro_set_video_refresh(retro_video_refresh_t cb) +{ + video_cb = cb; +} + +static uint32_t find_memory_type_from_requirements( + uint32_t device_requirements, uint32_t host_requirements) +{ + const VkPhysicalDeviceMemoryProperties *props = &vk.memory_properties; + for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) + { + if (device_requirements & (1u << i)) + { + if ((props->memoryTypes[i].propertyFlags & host_requirements) == host_requirements) + { + return i; + } + } + } + + return 0; +} + +static void vulkan_test_render(void) +{ + VkCommandBuffer cmd = vk.cmd[vk.index]; + + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkResetCommandBuffer(cmd, 0); + vkBeginCommandBuffer(cmd, &begin_info); + + VkImageMemoryBarrier prepare_rendering = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + prepare_rendering.srcAccessMask = 0; + prepare_rendering.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + prepare_rendering.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + prepare_rendering.newLayout = VK_IMAGE_LAYOUT_GENERAL; + prepare_rendering.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + prepare_rendering.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + prepare_rendering.image = vk.images[vk.index].create_info.image; + prepare_rendering.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + prepare_rendering.subresourceRange.levelCount = 1; + prepare_rendering.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(cmd, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + false, + 0, NULL, + 0, NULL, + 1, &prepare_rendering); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, vk.pipeline); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, + vk.pipeline_layout, 0, + 1, &vk.desc_set[vk.index], 0, NULL); + + const float constants[4] = { + 1.0f / BASE_WIDTH, + 1.0f / BASE_HEIGHT, + (float)frame_count++, + 0.0f, + }; + vkCmdPushConstants(cmd, vk.pipeline_layout, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, 16, constants); + + vkCmdDispatch(cmd, BASE_WIDTH / 8, BASE_HEIGHT / 8, 1); + + VkImageMemoryBarrier prepare_presentation = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + prepare_presentation.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + prepare_presentation.dstAccessMask = 0; + prepare_presentation.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + prepare_presentation.newLayout = VK_IMAGE_LAYOUT_GENERAL; + prepare_presentation.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + prepare_presentation.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + prepare_presentation.image = vk.images[vk.index].create_info.image; + prepare_presentation.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + prepare_presentation.subresourceRange.levelCount = 1; + prepare_presentation.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + false, + 0, NULL, + 0, NULL, + 1, &prepare_presentation); + + vkEndCommandBuffer(cmd); + + vulkan->lock_queue(vulkan->handle); + VkSubmitInfo submit = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + submit.commandBufferCount = 1; + submit.pCommandBuffers = &cmd; + submit.signalSemaphoreCount = 1; + submit.pSignalSemaphores = &vk.acquire_semaphores[vk.index]; + vkQueueSubmit(vulkan->queue, 1, &submit, VK_NULL_HANDLE); + vulkan->unlock_queue(vulkan->handle); +} + +static VkShaderModule create_shader_module(const uint32_t *data, size_t size) +{ + VkShaderModuleCreateInfo module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + VkShaderModule module; + module_info.codeSize = size; + module_info.pCode = data; + vkCreateShaderModule(vulkan->device, &module_info, NULL, &module); + return module; +} + +static void init_descriptor(void) +{ + VkDevice device = vulkan->device; + + VkDescriptorSetLayoutBinding binding = {0}; + binding.binding = 0; + binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + binding.pImmutableSamplers = NULL; + + const VkDescriptorPoolSize pool_sizes[1] = { + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk.num_swapchain_images }, + }; + + const VkPushConstantRange range = { + VK_SHADER_STAGE_COMPUTE_BIT, + 0, 16, + }; + + VkDescriptorSetLayoutCreateInfo set_layout_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + set_layout_info.bindingCount = 1; + set_layout_info.pBindings = &binding; + vkCreateDescriptorSetLayout(device, &set_layout_info, NULL, &vk.set_layout); + + VkPipelineLayoutCreateInfo layout_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &vk.set_layout; + layout_info.pushConstantRangeCount = 1; + layout_info.pPushConstantRanges = ⦥ + vkCreatePipelineLayout(device, &layout_info, NULL, &vk.pipeline_layout); + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.maxSets = vk.num_swapchain_images; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = pool_sizes; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + vkCreateDescriptorPool(device, &pool_info, NULL, &vk.desc_pool); + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = vk.desc_pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &vk.set_layout; + + for (unsigned i = 0; i < vk.num_swapchain_images; i++) + { + vkAllocateDescriptorSets(device, &alloc_info, &vk.desc_set[i]); + + VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + VkDescriptorImageInfo image_info; + + write.dstSet = vk.desc_set[i]; + write.dstBinding = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write.pImageInfo = &image_info; + + image_info.imageView = vk.images[i].image_view; + image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + image_info.sampler = VK_NULL_HANDLE; + + vkUpdateDescriptorSets(device, 1, &write, 0, NULL); + } +} + +static void init_pipeline(void) +{ + VkDevice device = vulkan->device; + + static const uint32_t raymarch_comp[] = +#include "shaders/raymarch.comp.inc" + ; + + VkComputePipelineCreateInfo pipe = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + + pipe.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipe.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipe.stage.module = create_shader_module(raymarch_comp, sizeof(raymarch_comp)); + pipe.stage.pName = "main"; + pipe.layout = vk.pipeline_layout; + + vkCreateComputePipelines(vulkan->device, vk.pipeline_cache, 1, &pipe, NULL, &vk.pipeline); + vkDestroyShaderModule(device, pipe.stage.module, NULL); +} + +static void init_swapchain(void) +{ + VkDevice device = vulkan->device; + + for (unsigned i = 0; i < vk.num_swapchain_images; i++) + { + VkImageCreateInfo image = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + + image.imageType = VK_IMAGE_TYPE_2D; + image.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + image.format = VK_FORMAT_R8G8B8A8_UNORM; + image.extent.width = BASE_WIDTH; + image.extent.height = BASE_HEIGHT; + image.extent.depth = 1; + image.samples = VK_SAMPLE_COUNT_1_BIT; + image.tiling = VK_IMAGE_TILING_OPTIMAL; + image.usage = + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image.mipLevels = 1; + image.arrayLayers = 1; + + vkCreateImage(device, &image, NULL, &vk.images[i].create_info.image); + + VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + VkMemoryRequirements mem_reqs; + + vkGetImageMemoryRequirements(device, vk.images[i].create_info.image, &mem_reqs); + alloc.allocationSize = mem_reqs.size; + alloc.memoryTypeIndex = find_memory_type_from_requirements( + mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkAllocateMemory(device, &alloc, NULL, &vk.image_memory[i]); + vkBindImageMemory(device, vk.images[i].create_info.image, vk.image_memory[i], 0); + + vk.images[i].create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vk.images[i].create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + vk.images[i].create_info.format = VK_FORMAT_R8G8B8A8_UNORM; + vk.images[i].create_info.subresourceRange.baseMipLevel = 0; + vk.images[i].create_info.subresourceRange.baseArrayLayer = 0; + vk.images[i].create_info.subresourceRange.levelCount = 1; + vk.images[i].create_info.subresourceRange.layerCount = 1; + vk.images[i].create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + vk.images[i].create_info.components.r = VK_COMPONENT_SWIZZLE_R; + vk.images[i].create_info.components.g = VK_COMPONENT_SWIZZLE_G; + vk.images[i].create_info.components.b = VK_COMPONENT_SWIZZLE_B; + vk.images[i].create_info.components.a = VK_COMPONENT_SWIZZLE_A; + + vkCreateImageView(device, &vk.images[i].create_info, + NULL, &vk.images[i].image_view); + vk.images[i].image_layout = VK_IMAGE_LAYOUT_GENERAL; + + VkSemaphoreCreateInfo sem_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + vkCreateSemaphore(device, &sem_info, NULL, &vk.acquire_semaphores[i]); + } +} + +static void init_command(void) +{ + VkCommandPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + + pool_info.queueFamilyIndex = vulkan->queue_index; + pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + for (unsigned i = 0; i < vk.num_swapchain_images; i++) + { + vkCreateCommandPool(vulkan->device, &pool_info, NULL, &vk.cmd_pool[i]); + info.commandPool = vk.cmd_pool[i]; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandBufferCount = 1; + vkAllocateCommandBuffers(vulkan->device, &info, &vk.cmd[i]); + } +} + +static void vulkan_test_init(void) +{ + vkGetPhysicalDeviceProperties(vulkan->gpu, &vk.gpu_properties); + vkGetPhysicalDeviceMemoryProperties(vulkan->gpu, &vk.memory_properties); + + unsigned num_images = 0; + uint32_t mask = vulkan->get_sync_index_mask(vulkan->handle); + for (unsigned i = 0; i < 32; i++) + if (mask & (1u << i)) + num_images = i + 1; + vk.num_swapchain_images = num_images; + vk.swapchain_mask = mask; + + init_command(); + init_swapchain(); + init_descriptor(); + + VkPipelineCacheCreateInfo pipeline_cache_info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; + vkCreatePipelineCache(vulkan->device, &pipeline_cache_info, + NULL, &vk.pipeline_cache); + + init_pipeline(); +} + +static void vulkan_test_deinit(void) +{ + if (!vulkan) + return; + + VkDevice device = vulkan->device; + vkDeviceWaitIdle(device); + + for (unsigned i = 0; i < vk.num_swapchain_images; i++) + { + vkDestroyImageView(device, vk.images[i].image_view, NULL); + vkFreeMemory(device, vk.image_memory[i], NULL); + vkDestroyImage(device, vk.images[i].create_info.image, NULL); + vkDestroySemaphore(device, vk.acquire_semaphores[i], NULL); + } + + vkFreeDescriptorSets(device, vk.desc_pool, vk.num_swapchain_images, vk.desc_set); + vkDestroyDescriptorPool(device, vk.desc_pool, NULL); + + vkDestroyPipeline(device, vk.pipeline, NULL); + vkDestroyDescriptorSetLayout(device, vk.set_layout, NULL); + vkDestroyPipelineLayout(device, vk.pipeline_layout, NULL); + vkDestroyPipelineCache(device, vk.pipeline_cache, NULL); + + for (unsigned i = 0; i < vk.num_swapchain_images; i++) + { + vkFreeCommandBuffers(device, vk.cmd_pool[i], 1, &vk.cmd[i]); + vkDestroyCommandPool(device, vk.cmd_pool[i], NULL); + } + + memset(&vk, 0, sizeof(vk)); +} + +void retro_run(void) +{ + input_poll_cb(); + + if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP)) + { + } + + /* Very lazy way to do this. */ + if (vulkan->get_sync_index_mask(vulkan->handle) != vk.swapchain_mask) + { + vulkan_test_deinit(); + vulkan_test_init(); + } + + vulkan->wait_sync_index(vulkan->handle); + + vk.index = vulkan->get_sync_index(vulkan->handle); + vulkan_test_render(); + vulkan->set_image(vulkan->handle, &vk.images[vk.index], 1, &vk.acquire_semaphores[vk.index], VK_QUEUE_FAMILY_IGNORED); + video_cb(RETRO_HW_FRAME_BUFFER_VALID, BASE_WIDTH, BASE_HEIGHT, 0); +} + +static void context_reset(void) +{ + fprintf(stderr, "Context reset!\n"); + if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void**)&vulkan) || !vulkan) + { + fprintf(stderr, "Failed to get HW rendering interface!\n"); + return; + } + + if (vulkan->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION) + { + fprintf(stderr, "HW render interface mismatch, expected %u, got %u!\n", + RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION, vulkan->interface_version); + vulkan = NULL; + return; + } + + vulkan_symbol_wrapper_init(vulkan->get_instance_proc_addr); + vulkan_symbol_wrapper_load_core_instance_symbols(vulkan->instance); + vulkan_symbol_wrapper_load_core_device_symbols(vulkan->device); + vulkan_test_init(); +} + +static void context_destroy(void) +{ + fprintf(stderr, "Context destroy!\n"); + vulkan_test_deinit(); + vulkan = NULL; + memset(&vk, 0, sizeof(vk)); +} + +static const VkApplicationInfo *get_application_info(void) +{ + static const VkApplicationInfo info = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, + NULL, + "libretro-test-vulkan-async-compute", + 0, + "libretro-test-vulkan-async-compute", + 0, + VK_MAKE_VERSION(1, 0, 18), + }; + return &info; +} + +static bool retro_init_hw_context(void) +{ + hw_render.context_type = RETRO_HW_CONTEXT_VULKAN; + hw_render.version_major = VK_MAKE_VERSION(1, 0, 18); + hw_render.version_minor = 0; + hw_render.context_reset = context_reset; + hw_render.context_destroy = context_destroy; + hw_render.cache_context = false; + if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render)) + return false; + + static const struct retro_hw_render_context_negotiation_interface_vulkan iface = { + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN, + RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, + + get_application_info, + NULL, + }; + + environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, (void*)&iface); + + return true; +} + +bool retro_load_game(const struct retro_game_info *info) +{ + if (!retro_init_hw_context()) + { + fprintf(stderr, "HW Context could not be initialized, exiting...\n"); + return false; + } + + fprintf(stderr, "Loaded game!\n"); + (void)info; + + frame_count = 0; + return true; +} + +void retro_unload_game(void) +{} + +unsigned retro_get_region(void) +{ + return RETRO_REGION_NTSC; +} + +bool retro_load_game_special(unsigned type, const struct retro_game_info *info, size_t num) +{ + (void)type; + (void)info; + (void)num; + return false; +} + +size_t retro_serialize_size(void) +{ + return 0; +} + +bool retro_serialize(void *data, size_t size) +{ + (void)data; + (void)size; + return false; +} + +bool retro_unserialize(const void *data, size_t size) +{ + (void)data; + (void)size; + return false; +} + +void *retro_get_memory_data(unsigned id) +{ + (void)id; + return NULL; +} + +size_t retro_get_memory_size(unsigned id) +{ + (void)id; + return 0; +} + +void retro_reset(void) +{} + +void retro_cheat_reset(void) +{} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) +{ + (void)index; + (void)enabled; + (void)code; +} + diff --git a/cores/libretro-test-vulkan-async-compute/link.T b/cores/libretro-test-vulkan-async-compute/link.T new file mode 100644 index 0000000000..b0c262db9e --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/link.T @@ -0,0 +1,5 @@ +{ + global: retro_*; + local: *; +}; + diff --git a/cores/libretro-test-vulkan-async-compute/shaders/Makefile b/cores/libretro-test-vulkan-async-compute/shaders/Makefile new file mode 100644 index 0000000000..f55f5114fe --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/shaders/Makefile @@ -0,0 +1,15 @@ +COMP_SHADERS := $(wildcard *.comp) +SPIRV := $(COMP_SHADERS:.comp=.comp.inc) + +GLSLANG := glslc +GLSLFLAGS := -mfmt=c + +all: $(SPIRV) + +%.comp.inc: %.comp + $(GLSLANG) $(GLSLFLAGS) -o $@ $< + +clean: + rm -f $(SPIRV) + +.PHONY: clean diff --git a/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp b/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp new file mode 100644 index 0000000000..a8adc23d4d --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp @@ -0,0 +1,18 @@ +#version 310 es +layout(local_size_x = 8, local_size_y = 8) in; + +layout(rgba8, set = 0, binding = 0) uniform writeonly mediump image2D uImage; + +layout(push_constant, std430) uniform PushConstants +{ + vec2 inv_resolution; + float frame; + float dummy; +} constants; + +void main() +{ + vec2 uv = (vec2(gl_GlobalInvocationID.xy) + 0.5) * constants.inv_resolution; + vec4 color = vec4(sin(uv.x * 50.0 + constants.frame * 0.1) + 0.5, cos(uv.y * 55.0 + constants.frame * 0.2), 0.2, 1.0); + imageStore(uImage, ivec2(gl_GlobalInvocationID.xy), color); +} diff --git a/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp.inc b/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp.inc new file mode 100644 index 0000000000..e347663d2d --- /dev/null +++ b/cores/libretro-test-vulkan-async-compute/shaders/raymarch.comp.inc @@ -0,0 +1,117 @@ +{0x07230203,0x00010000,0x00080001,0x00000048, +0x00000000,0x00020011,0x00000001,0x0006000b, +0x00000001,0x4c534c47,0x6474732e,0x3035342e, +0x00000000,0x0003000e,0x00000000,0x00000001, +0x0006000f,0x00000005,0x00000004,0x6e69616d, +0x00000000,0x0000000d,0x00060010,0x00000004, +0x00000011,0x00000008,0x00000008,0x00000001, +0x00030003,0x00000001,0x00000136,0x000a0004, +0x475f4c47,0x4c474f4f,0x70635f45,0x74735f70, +0x5f656c79,0x656e696c,0x7269645f,0x69746365, +0x00006576,0x00080004,0x475f4c47,0x4c474f4f, +0x6e695f45,0x64756c63,0x69645f65,0x74636572, +0x00657669,0x00040005,0x00000004,0x6e69616d, +0x00000000,0x00030005,0x00000009,0x00007675, +0x00080005,0x0000000d,0x475f6c67,0x61626f6c, +0x766e496c,0x7461636f,0x496e6f69,0x00000044, +0x00060005,0x00000015,0x68737550,0x736e6f43, +0x746e6174,0x00000073,0x00070006,0x00000015, +0x00000000,0x5f766e69,0x6f736572,0x6974756c, +0x00006e6f,0x00050006,0x00000015,0x00000001, +0x6d617266,0x00000065,0x00050006,0x00000015, +0x00000002,0x6d6d7564,0x00000079,0x00050005, +0x00000017,0x736e6f63,0x746e6174,0x00000073, +0x00040005,0x00000020,0x6f6c6f63,0x00000072, +0x00040005,0x0000003f,0x616d4975,0x00006567, +0x00040047,0x0000000d,0x0000000b,0x0000001c, +0x00050048,0x00000015,0x00000000,0x00000023, +0x00000000,0x00050048,0x00000015,0x00000001, +0x00000023,0x00000008,0x00050048,0x00000015, +0x00000002,0x00000023,0x0000000c,0x00030047, +0x00000015,0x00000002,0x00030047,0x0000003f, +0x00000000,0x00040047,0x0000003f,0x00000022, +0x00000000,0x00040047,0x0000003f,0x00000021, +0x00000000,0x00030047,0x0000003f,0x00000019, +0x00030047,0x00000040,0x00000000,0x00040047, +0x00000047,0x0000000b,0x00000019,0x00020013, +0x00000002,0x00030021,0x00000003,0x00000002, +0x00030016,0x00000006,0x00000020,0x00040017, +0x00000007,0x00000006,0x00000002,0x00040020, +0x00000008,0x00000007,0x00000007,0x00040015, +0x0000000a,0x00000020,0x00000000,0x00040017, +0x0000000b,0x0000000a,0x00000003,0x00040020, +0x0000000c,0x00000001,0x0000000b,0x0004003b, +0x0000000c,0x0000000d,0x00000001,0x00040017, +0x0000000e,0x0000000a,0x00000002,0x0004002b, +0x00000006,0x00000012,0x3f000000,0x0005001e, +0x00000015,0x00000007,0x00000006,0x00000006, +0x00040020,0x00000016,0x00000009,0x00000015, +0x0004003b,0x00000016,0x00000017,0x00000009, +0x00040015,0x00000018,0x00000020,0x00000001, +0x0004002b,0x00000018,0x00000019,0x00000000, +0x00040020,0x0000001a,0x00000009,0x00000007, +0x00040017,0x0000001e,0x00000006,0x00000004, +0x00040020,0x0000001f,0x00000007,0x0000001e, +0x0004002b,0x0000000a,0x00000021,0x00000000, +0x00040020,0x00000022,0x00000007,0x00000006, +0x0004002b,0x00000006,0x00000025,0x42480000, +0x0004002b,0x00000018,0x00000027,0x00000001, +0x00040020,0x00000028,0x00000009,0x00000006, +0x0004002b,0x00000006,0x0000002b,0x3dcccccd, +0x0004002b,0x0000000a,0x00000030,0x00000001, +0x0004002b,0x00000006,0x00000033,0x425c0000, +0x0004002b,0x00000006,0x00000037,0x3e4ccccd, +0x0004002b,0x00000006,0x0000003b,0x3f800000, +0x00090019,0x0000003d,0x00000006,0x00000001, +0x00000000,0x00000000,0x00000000,0x00000002, +0x00000004,0x00040020,0x0000003e,0x00000000, +0x0000003d,0x0004003b,0x0000003e,0x0000003f, +0x00000000,0x00040017,0x00000043,0x00000018, +0x00000002,0x0004002b,0x0000000a,0x00000046, +0x00000008,0x0006002c,0x0000000b,0x00000047, +0x00000046,0x00000046,0x00000030,0x00050036, +0x00000002,0x00000004,0x00000000,0x00000003, +0x000200f8,0x00000005,0x0004003b,0x00000008, +0x00000009,0x00000007,0x0004003b,0x0000001f, +0x00000020,0x00000007,0x0004003d,0x0000000b, +0x0000000f,0x0000000d,0x0007004f,0x0000000e, +0x00000010,0x0000000f,0x0000000f,0x00000000, +0x00000001,0x00040070,0x00000007,0x00000011, +0x00000010,0x00050050,0x00000007,0x00000013, +0x00000012,0x00000012,0x00050081,0x00000007, +0x00000014,0x00000011,0x00000013,0x00050041, +0x0000001a,0x0000001b,0x00000017,0x00000019, +0x0004003d,0x00000007,0x0000001c,0x0000001b, +0x00050085,0x00000007,0x0000001d,0x00000014, +0x0000001c,0x0003003e,0x00000009,0x0000001d, +0x00050041,0x00000022,0x00000023,0x00000009, +0x00000021,0x0004003d,0x00000006,0x00000024, +0x00000023,0x00050085,0x00000006,0x00000026, +0x00000024,0x00000025,0x00050041,0x00000028, +0x00000029,0x00000017,0x00000027,0x0004003d, +0x00000006,0x0000002a,0x00000029,0x00050085, +0x00000006,0x0000002c,0x0000002a,0x0000002b, +0x00050081,0x00000006,0x0000002d,0x00000026, +0x0000002c,0x0006000c,0x00000006,0x0000002e, +0x00000001,0x0000000d,0x0000002d,0x00050081, +0x00000006,0x0000002f,0x0000002e,0x00000012, +0x00050041,0x00000022,0x00000031,0x00000009, +0x00000030,0x0004003d,0x00000006,0x00000032, +0x00000031,0x00050085,0x00000006,0x00000034, +0x00000032,0x00000033,0x00050041,0x00000028, +0x00000035,0x00000017,0x00000027,0x0004003d, +0x00000006,0x00000036,0x00000035,0x00050085, +0x00000006,0x00000038,0x00000036,0x00000037, +0x00050081,0x00000006,0x00000039,0x00000034, +0x00000038,0x0006000c,0x00000006,0x0000003a, +0x00000001,0x0000000e,0x00000039,0x00070050, +0x0000001e,0x0000003c,0x0000002f,0x0000003a, +0x00000037,0x0000003b,0x0003003e,0x00000020, +0x0000003c,0x0004003d,0x0000003d,0x00000040, +0x0000003f,0x0004003d,0x0000000b,0x00000041, +0x0000000d,0x0007004f,0x0000000e,0x00000042, +0x00000041,0x00000041,0x00000000,0x00000001, +0x0004007c,0x00000043,0x00000044,0x00000042, +0x0004003d,0x0000001e,0x00000045,0x00000020, +0x00040063,0x00000040,0x00000044,0x00000045, +0x000100fd,0x00010038}