mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
(cores) Remove libretro-test-vulkan and libretro-test-vulkan-async-compute - these are part of libretro-samples now
This commit is contained in:
parent
efbe083a5f
commit
00ec309d76
@ -1,62 +0,0 @@
|
||||
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 -I../../gfx/include
|
||||
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
|
||||
|
@ -1,25 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := retro
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
LOCAL_CFLAGS += -DANDROID_ARM
|
||||
LOCAL_ARM_MODE := arm
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),x86)
|
||||
LOCAL_CFLAGS += -DANDROID_X86
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),mips)
|
||||
LOCAL_CFLAGS += -DANDROID_MIPS
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += ../libretro-test.c \
|
||||
../../../libretro-common/vulkan/vulkan_symbol_wrapper.c
|
||||
LOCAL_CFLAGS += -O2 -Wall -std=gnu99 -ffast-math -DGLES -DHAVE_OPENGLES2 -I../../../libretro-common/include -I../../../gfx/include
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
@ -1,3 +0,0 @@
|
||||
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 mips mips64
|
||||
APP_PLATFORM := android-9
|
||||
|
@ -1,805 +0,0 @@
|
||||
#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>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
static struct retro_hw_render_callback hw_render;
|
||||
static const struct retro_hw_render_interface_vulkan *vulkan;
|
||||
static unsigned frame_count;
|
||||
static VkQueue async_queue;
|
||||
static uint32_t async_queue_index;
|
||||
|
||||
#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];
|
||||
|
||||
bool need_acquire[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;
|
||||
|
||||
if (vk.need_acquire[vk.index])
|
||||
{
|
||||
prepare_rendering.srcQueueFamilyIndex = vulkan->queue_index;
|
||||
prepare_rendering.dstQueueFamilyIndex = async_queue_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
|
||||
if (async_queue && vulkan->queue_index != async_queue_index)
|
||||
{
|
||||
prepare_presentation.srcQueueFamilyIndex = async_queue_index;
|
||||
prepare_presentation.dstQueueFamilyIndex = vulkan->queue_index;
|
||||
vk.need_acquire[vk.index] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
prepare_presentation.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
prepare_presentation.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
vk.need_acquire[vk.index] = false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!async_queue)
|
||||
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(async_queue != VK_NULL_HANDLE ? async_queue : vulkan->queue,
|
||||
1, &submit, VK_NULL_HANDLE);
|
||||
|
||||
if (!async_queue)
|
||||
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;
|
||||
|
||||
uint32_t share_queues[] = { async_queue_index, vulkan->queue_index };
|
||||
if (async_queue && async_queue_index != vulkan->queue_index)
|
||||
{
|
||||
image.queueFamilyIndexCount = 2;
|
||||
image.pQueueFamilyIndices = share_queues;
|
||||
}
|
||||
|
||||
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 = async_queue != VK_NULL_HANDLE ?
|
||||
async_queue_index : 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],
|
||||
async_queue && async_queue_index != vulkan->queue_index ?
|
||||
async_queue_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 create_device(struct retro_vulkan_context *context,
|
||||
VkInstance instance,
|
||||
VkPhysicalDevice gpu,
|
||||
VkSurfaceKHR surface,
|
||||
PFN_vkGetInstanceProcAddr get_instance_proc_addr,
|
||||
const char **required_device_extensions,
|
||||
unsigned num_required_device_extensions,
|
||||
const char **required_device_layers,
|
||||
unsigned num_required_device_layers,
|
||||
const VkPhysicalDeviceFeatures *required_features)
|
||||
{
|
||||
async_queue = VK_NULL_HANDLE;
|
||||
vulkan_symbol_wrapper_init(get_instance_proc_addr);
|
||||
vulkan_symbol_wrapper_load_core_symbols(instance);
|
||||
|
||||
if (gpu == VK_NULL_HANDLE)
|
||||
{
|
||||
uint32_t gpu_count;
|
||||
vkEnumeratePhysicalDevices(instance, &gpu_count, NULL);
|
||||
if (!gpu_count)
|
||||
return false;
|
||||
VkPhysicalDevice *gpus = calloc(gpu_count, sizeof(*gpus));
|
||||
if (!gpus)
|
||||
return false;
|
||||
|
||||
vkEnumeratePhysicalDevices(instance, &gpu_count, gpus);
|
||||
gpu = gpus[0];
|
||||
free(gpus);
|
||||
}
|
||||
|
||||
context->gpu = gpu;
|
||||
|
||||
uint32_t queue_count;
|
||||
VkQueueFamilyProperties *queue_properties = NULL;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, NULL);
|
||||
if (queue_count < 1)
|
||||
return false;
|
||||
queue_properties = calloc(queue_count, sizeof(*queue_properties));
|
||||
if (!queue_properties)
|
||||
return false;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, queue_properties);
|
||||
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance,
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
}
|
||||
|
||||
bool found_queue = false;
|
||||
for (uint32_t i = 0; i < queue_count; i++)
|
||||
{
|
||||
VkBool32 supported = surface == VK_NULL_HANDLE;
|
||||
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
gpu, i, surface, &supported);
|
||||
}
|
||||
|
||||
VkQueueFlags required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
|
||||
if (supported && ((queue_properties[i].queueFlags & required) == required))
|
||||
{
|
||||
context->queue_family_index = i;
|
||||
found_queue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_queue)
|
||||
{
|
||||
free(queue_properties);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool same_queue_async = false;
|
||||
if (queue_properties[context->queue_family_index].queueCount >= 2)
|
||||
same_queue_async = true;
|
||||
|
||||
if (!same_queue_async)
|
||||
{
|
||||
found_queue = false;
|
||||
for (uint32_t i = 0; i < queue_count; i++)
|
||||
{
|
||||
if (i == context->queue_family_index)
|
||||
continue;
|
||||
|
||||
VkQueueFlags required = VK_QUEUE_COMPUTE_BIT;
|
||||
if ((queue_properties[i].queueFlags & required) == required)
|
||||
{
|
||||
async_queue_index = i;
|
||||
found_queue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
async_queue_index = context->queue_family_index;
|
||||
|
||||
free(queue_properties);
|
||||
if (!found_queue)
|
||||
return false;
|
||||
|
||||
const float prios[] = { 0.5f, 0.5f };
|
||||
VkDeviceQueueCreateInfo queues[2] = {
|
||||
{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO },
|
||||
{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO },
|
||||
};
|
||||
|
||||
if (same_queue_async)
|
||||
{
|
||||
queues[0].queueFamilyIndex = context->queue_family_index;
|
||||
queues[0].queueCount = 2;
|
||||
queues[0].pQueuePriorities = prios;
|
||||
}
|
||||
else
|
||||
{
|
||||
queues[0].queueFamilyIndex = context->queue_family_index;
|
||||
queues[0].queueCount = 1;
|
||||
queues[0].pQueuePriorities = &prios[0];
|
||||
queues[1].queueFamilyIndex = async_queue_index;
|
||||
queues[1].queueCount = 1;
|
||||
queues[1].pQueuePriorities = &prios[1];
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
|
||||
device_info.enabledExtensionCount = num_required_device_extensions;
|
||||
device_info.ppEnabledExtensionNames = required_device_extensions;
|
||||
device_info.enabledLayerCount = num_required_device_layers;
|
||||
device_info.ppEnabledLayerNames = required_device_layers;
|
||||
device_info.queueCreateInfoCount = same_queue_async ? 1 : 2;
|
||||
device_info.pQueueCreateInfos = queues;
|
||||
|
||||
if (vkCreateDevice(gpu, &device_info, NULL, &context->device) != VK_SUCCESS)
|
||||
return false;
|
||||
|
||||
vkGetDeviceQueue(context->device, context->queue_family_index, 0, &context->queue);
|
||||
if (same_queue_async)
|
||||
vkGetDeviceQueue(context->device, context->queue_family_index, 1, &async_queue);
|
||||
else
|
||||
vkGetDeviceQueue(context->device, async_queue_index, 0, &async_queue);
|
||||
|
||||
context->presentation_queue = context->queue;
|
||||
context->presentation_queue_family_index = context->queue_family_index;
|
||||
return true;
|
||||
}
|
||||
|
||||
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,
|
||||
create_device,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
global: retro_*;
|
||||
local: *;
|
||||
};
|
||||
|
@ -1,15 +0,0 @@
|
||||
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
|
@ -1,18 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
{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}
|
@ -1,62 +0,0 @@
|
||||
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
|
||||
|
||||
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 -I../../gfx/include
|
||||
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
|
||||
|
@ -1,25 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := retro
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
LOCAL_CFLAGS += -DANDROID_ARM
|
||||
LOCAL_ARM_MODE := arm
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),x86)
|
||||
LOCAL_CFLAGS += -DANDROID_X86
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH),mips)
|
||||
LOCAL_CFLAGS += -DANDROID_MIPS
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += ../libretro-test.c \
|
||||
../../../libretro-common/vulkan/vulkan_symbol_wrapper.c
|
||||
LOCAL_CFLAGS += -O2 -Wall -std=gnu99 -ffast-math -DGLES -DHAVE_OPENGLES2 -I../../../libretro-common/include -I../../../gfx/include
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
@ -1,3 +0,0 @@
|
||||
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 mips mips64
|
||||
APP_PLATFORM := android-9
|
||||
|
@ -1,877 +0,0 @@
|
||||
#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>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
static struct retro_hw_render_callback hw_render;
|
||||
static const struct retro_hw_render_interface_vulkan *vulkan;
|
||||
|
||||
#define BASE_WIDTH 320
|
||||
#define BASE_HEIGHT 240
|
||||
#define MAX_SYNC 8
|
||||
|
||||
static unsigned width = BASE_WIDTH;
|
||||
static unsigned height = BASE_HEIGHT;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
};
|
||||
|
||||
struct vulkan_data
|
||||
{
|
||||
unsigned index;
|
||||
unsigned num_swapchain_images;
|
||||
uint32_t swapchain_mask;
|
||||
struct buffer vbo;
|
||||
struct buffer ubo[MAX_SYNC];
|
||||
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
VkPhysicalDeviceProperties gpu_properties;
|
||||
|
||||
VkDescriptorSetLayout set_layout;
|
||||
VkDescriptorPool desc_pool;
|
||||
VkDescriptorSet desc_set[MAX_SYNC];
|
||||
|
||||
VkPipelineCache pipeline_cache;
|
||||
VkPipelineLayout pipeline_layout;
|
||||
VkRenderPass render_pass;
|
||||
VkPipeline pipeline;
|
||||
|
||||
struct retro_vulkan_image images[MAX_SYNC];
|
||||
VkDeviceMemory image_memory[MAX_SYNC];
|
||||
VkFramebuffer framebuffers[MAX_SYNC];
|
||||
VkCommandPool cmd_pool[MAX_SYNC];
|
||||
VkCommandBuffer cmd[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 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;
|
||||
|
||||
struct retro_variable variables[] = {
|
||||
{
|
||||
"testvulkan_resolution",
|
||||
"Internal resolution; 320x240|360x480|480x272|512x384|512x512|640x240|640x448|640x480|720x576|800x600|960x720|1024x768|1024x1024|1280x720|1280x960|1600x1200|1920x1080|1920x1440|1920x1600|2048x2048",
|
||||
},
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
bool no_rom = true;
|
||||
cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom);
|
||||
cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
|
||||
}
|
||||
|
||||
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 update_ubo(void)
|
||||
{
|
||||
static unsigned frame;
|
||||
float c = cosf(frame * 0.01f);
|
||||
float s = sinf(frame * 0.01f);
|
||||
frame++;
|
||||
|
||||
float tmp[16] = {0.0f};
|
||||
tmp[ 0] = c;
|
||||
tmp[ 1] = s;
|
||||
tmp[ 4] = -s;
|
||||
tmp[ 5] = c;
|
||||
tmp[10] = 1.0f;
|
||||
tmp[15] = 1.0f;
|
||||
|
||||
float *mvp = NULL;
|
||||
vkMapMemory(vulkan->device, vk.ubo[vk.index].memory,
|
||||
0, 16 * sizeof(float), 0, (void**)&mvp);
|
||||
memcpy(mvp, tmp, sizeof(tmp));
|
||||
vkUnmapMemory(vulkan->device, vk.ubo[vk.index].memory);
|
||||
}
|
||||
|
||||
static void vulkan_test_render(void)
|
||||
{
|
||||
update_ubo();
|
||||
|
||||
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_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
||||
prepare_rendering.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
prepare_rendering.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
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_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
false,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
1, &prepare_rendering);
|
||||
|
||||
VkClearValue clear_value;
|
||||
clear_value.color.float32[0] = 0.8f;
|
||||
clear_value.color.float32[1] = 0.6f;
|
||||
clear_value.color.float32[2] = 0.2f;
|
||||
clear_value.color.float32[3] = 1.0f;
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp_begin.renderPass = vk.render_pass;
|
||||
rp_begin.framebuffer = vk.framebuffers[vk.index];
|
||||
rp_begin.renderArea.extent.width = width;
|
||||
rp_begin.renderArea.extent.height = height;
|
||||
rp_begin.clearValueCount = 1;
|
||||
rp_begin.pClearValues = &clear_value;
|
||||
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, vk.pipeline);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
vk.pipeline_layout, 0,
|
||||
1, &vk.desc_set[vk.index], 0, NULL);
|
||||
|
||||
VkViewport vp = { 0 };
|
||||
vp.x = 0.0f;
|
||||
vp.y = 0.0f;
|
||||
vp.width = width;
|
||||
vp.height = height;
|
||||
vp.minDepth = 0.0f;
|
||||
vp.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
scissor.extent.width = width;
|
||||
scissor.extent.height = height;
|
||||
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &vk.vbo.buffer, &offset);
|
||||
|
||||
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
VkImageMemoryBarrier prepare_presentation = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
prepare_presentation.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
prepare_presentation.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
prepare_presentation.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
prepare_presentation.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
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_ALL_GRAPHICS_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
false,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
1, &prepare_presentation);
|
||||
|
||||
vkEndCommandBuffer(cmd);
|
||||
}
|
||||
|
||||
static struct buffer create_buffer(const void *initial, size_t size, VkBufferUsageFlags usage)
|
||||
{
|
||||
struct buffer buffer;
|
||||
VkDevice device = vulkan->device;
|
||||
|
||||
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
info.usage = usage;
|
||||
info.size = size;
|
||||
|
||||
vkCreateBuffer(device, &info, NULL, &buffer.buffer);
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetBufferMemoryRequirements(device, buffer.buffer, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
alloc.memoryTypeIndex = find_memory_type_from_requirements(mem_reqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vkAllocateMemory(device, &alloc, NULL, &buffer.memory);
|
||||
vkBindBufferMemory(device, buffer.buffer, buffer.memory, 0);
|
||||
|
||||
if (initial)
|
||||
{
|
||||
void *ptr;
|
||||
vkMapMemory(device, buffer.memory, 0, size, 0, &ptr);
|
||||
memcpy(ptr, initial, size);
|
||||
vkUnmapMemory(device, buffer.memory);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void init_vertex_buffer(void)
|
||||
{
|
||||
static const float data[] = {
|
||||
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // vec4 position, vec4 color
|
||||
-0.5f, +0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
|
||||
+0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||
};
|
||||
|
||||
vk.vbo = create_buffer(data, sizeof(data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||
}
|
||||
|
||||
static void init_uniform_buffer(void)
|
||||
{
|
||||
for (unsigned i = 0; i < vk.num_swapchain_images; i++)
|
||||
{
|
||||
vk.ubo[i] = create_buffer(NULL, 16 * sizeof(float),
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
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_UNIFORM_BUFFER;
|
||||
binding.descriptorCount = 1;
|
||||
binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
binding.pImmutableSamplers = NULL;
|
||||
|
||||
const VkDescriptorPoolSize pool_sizes[1] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk.num_swapchain_images },
|
||||
};
|
||||
|
||||
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;
|
||||
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 };
|
||||
VkDescriptorBufferInfo buffer_info;
|
||||
|
||||
write.dstSet = vk.desc_set[i];
|
||||
write.dstBinding = 0;
|
||||
write.descriptorCount = 1;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
write.pBufferInfo = &buffer_info;
|
||||
|
||||
buffer_info.buffer = vk.ubo[i].buffer;
|
||||
buffer_info.offset = 0;
|
||||
buffer_info.range = 16 * sizeof(float);
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_pipeline(void)
|
||||
{
|
||||
VkDevice device = vulkan->device;
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
||||
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
VkVertexInputAttributeDescription attributes[2] = {{ 0 }};
|
||||
attributes[0].location = 0;
|
||||
attributes[0].binding = 0;
|
||||
attributes[0].format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
attributes[0].offset = 0;
|
||||
attributes[1].location = 1;
|
||||
attributes[1].binding = 0;
|
||||
attributes[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
attributes[1].offset = 4 * sizeof(float);
|
||||
|
||||
VkVertexInputBindingDescription binding = { 0 };
|
||||
binding.binding = 0;
|
||||
binding.stride = sizeof(float) * 8;
|
||||
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
||||
vertex_input.vertexBindingDescriptionCount = 1;
|
||||
vertex_input.pVertexBindingDescriptions = &binding;
|
||||
vertex_input.vertexAttributeDescriptionCount = 2;
|
||||
vertex_input.pVertexAttributeDescriptions = attributes;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
raster.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
raster.depthClampEnable = false;
|
||||
raster.rasterizerDiscardEnable = false;
|
||||
raster.depthBiasEnable = false;
|
||||
raster.lineWidth = 1.0f;
|
||||
|
||||
VkPipelineColorBlendAttachmentState blend_attachment = { 0 };
|
||||
blend_attachment.blendEnable = false;
|
||||
blend_attachment.colorWriteMask = 0xf;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo blend = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
||||
blend.attachmentCount = 1;
|
||||
blend.pAttachments = &blend_attachment;
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewport = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
||||
viewport.viewportCount = 1;
|
||||
viewport.scissorCount = 1;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depth_stencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
|
||||
depth_stencil.depthTestEnable = false;
|
||||
depth_stencil.depthWriteEnable = false;
|
||||
depth_stencil.depthBoundsTestEnable = false;
|
||||
depth_stencil.stencilTestEnable = false;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
||||
multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
static const VkDynamicState dynamics[] = {
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
VkPipelineDynamicStateCreateInfo dynamic = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
dynamic.pDynamicStates = dynamics;
|
||||
dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]);
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[2] = {
|
||||
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO },
|
||||
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO },
|
||||
};
|
||||
|
||||
static const uint32_t triangle_vert[] =
|
||||
#include "shaders/triangle.vert.inc"
|
||||
;
|
||||
|
||||
static const uint32_t triangle_frag[] =
|
||||
#include "shaders/triangle.frag.inc"
|
||||
;
|
||||
|
||||
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shader_stages[0].module = create_shader_module(triangle_vert, sizeof(triangle_vert));
|
||||
shader_stages[0].pName = "main";
|
||||
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shader_stages[1].module = create_shader_module(triangle_frag, sizeof(triangle_frag));
|
||||
shader_stages[1].pName = "main";
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipe = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
||||
pipe.stageCount = 2;
|
||||
pipe.pStages = shader_stages;
|
||||
pipe.pVertexInputState = &vertex_input;
|
||||
pipe.pInputAssemblyState = &input_assembly;
|
||||
pipe.pRasterizationState = &raster;
|
||||
pipe.pColorBlendState = &blend;
|
||||
pipe.pMultisampleState = &multisample;
|
||||
pipe.pViewportState = &viewport;
|
||||
pipe.pDepthStencilState = &depth_stencil;
|
||||
pipe.pDynamicState = &dynamic;
|
||||
pipe.renderPass = vk.render_pass;
|
||||
pipe.layout = vk.pipeline_layout;
|
||||
|
||||
vkCreateGraphicsPipelines(vulkan->device, vk.pipeline_cache, 1, &pipe, NULL, &vk.pipeline);
|
||||
|
||||
vkDestroyShaderModule(device, shader_stages[0].module, NULL);
|
||||
vkDestroyShaderModule(device, shader_stages[1].module, NULL);
|
||||
}
|
||||
|
||||
static void init_render_pass(VkFormat format)
|
||||
{
|
||||
VkAttachmentDescription attachment = { 0 };
|
||||
attachment.format = format;
|
||||
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference color_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
|
||||
VkSubpassDescription subpass = { 0 };
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_ref;
|
||||
|
||||
VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp_info.attachmentCount = 1;
|
||||
rp_info.pAttachments = &attachment;
|
||||
rp_info.subpassCount = 1;
|
||||
rp_info.pSubpasses = &subpass;
|
||||
vkCreateRenderPass(vulkan->device, &rp_info, NULL, &vk.render_pass);
|
||||
}
|
||||
|
||||
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 = width;
|
||||
image.extent.height = height;
|
||||
image.extent.depth = 1;
|
||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image.usage =
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_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_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
VkFramebufferCreateInfo fb_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
fb_info.renderPass = vk.render_pass;
|
||||
fb_info.attachmentCount = 1;
|
||||
fb_info.pAttachments = &vk.images[i].image_view;
|
||||
fb_info.width = width;
|
||||
fb_info.height = height;
|
||||
fb_info.layers = 1;
|
||||
|
||||
vkCreateFramebuffer(device, &fb_info, NULL, &vk.framebuffers[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_uniform_buffer();
|
||||
init_vertex_buffer();
|
||||
init_command();
|
||||
init_descriptor();
|
||||
|
||||
VkPipelineCacheCreateInfo pipeline_cache_info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||
vkCreatePipelineCache(vulkan->device, &pipeline_cache_info,
|
||||
NULL, &vk.pipeline_cache);
|
||||
|
||||
init_render_pass(VK_FORMAT_R8G8B8A8_UNORM);
|
||||
init_pipeline();
|
||||
init_swapchain();
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
vkDestroyFramebuffer(device, vk.framebuffers[i], NULL);
|
||||
vkDestroyImageView(device, vk.images[i].image_view, NULL);
|
||||
vkFreeMemory(device, vk.image_memory[i], NULL);
|
||||
vkDestroyImage(device, vk.images[i].create_info.image, NULL);
|
||||
|
||||
vkFreeMemory(device, vk.ubo[i].memory, NULL);
|
||||
vkDestroyBuffer(device, vk.ubo[i].buffer, NULL);
|
||||
}
|
||||
|
||||
vkFreeDescriptorSets(device, vk.desc_pool, vk.num_swapchain_images, vk.desc_set);
|
||||
vkDestroyDescriptorPool(device, vk.desc_pool, NULL);
|
||||
|
||||
vkDestroyRenderPass(device, vk.render_pass, NULL);
|
||||
vkDestroyPipeline(device, vk.pipeline, NULL);
|
||||
vkDestroyDescriptorSetLayout(device, vk.set_layout, NULL);
|
||||
vkDestroyPipelineLayout(device, vk.pipeline_layout, NULL);
|
||||
|
||||
vkFreeMemory(device, vk.vbo.memory, NULL);
|
||||
vkDestroyBuffer(device, vk.vbo.buffer, 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));
|
||||
}
|
||||
|
||||
static void update_variables(void)
|
||||
{
|
||||
struct retro_variable var = {
|
||||
.key = "testvulkan_resolution",
|
||||
};
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
|
||||
{
|
||||
char *pch;
|
||||
char str[100];
|
||||
snprintf(str, sizeof(str), "%s", var.value);
|
||||
|
||||
pch = strtok(str, "x");
|
||||
if (pch)
|
||||
width = strtoul(pch, NULL, 0);
|
||||
pch = strtok(NULL, "x");
|
||||
if (pch)
|
||||
height = strtoul(pch, NULL, 0);
|
||||
|
||||
fprintf(stderr, "[libretro-test]: Got size: %u x %u.\n", width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void retro_run(void)
|
||||
{
|
||||
bool updated = false;
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
|
||||
update_variables();
|
||||
|
||||
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], 0, NULL, VK_QUEUE_FAMILY_IGNORED);
|
||||
vulkan->set_command_buffers(vulkan->handle, 1, &vk.cmd[vk.index]);
|
||||
video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, 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",
|
||||
0,
|
||||
"libretro-test-vulkan",
|
||||
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 = true;
|
||||
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)
|
||||
{
|
||||
update_variables();
|
||||
|
||||
if (!retro_init_hw_context())
|
||||
{
|
||||
fprintf(stderr, "HW Context could not be initialized, exiting...\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Loaded game!\n");
|
||||
(void)info;
|
||||
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;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
global: retro_*;
|
||||
local: *;
|
||||
};
|
||||
|
@ -1,19 +0,0 @@
|
||||
VERT_SHADERS := $(wildcard *.vert)
|
||||
FRAG_SHADERS := $(wildcard *.frag)
|
||||
SPIRV := $(VERT_SHADERS:.vert=.vert.inc) $(FRAG_SHADERS:.frag=.frag.inc)
|
||||
|
||||
GLSLANG := glslc
|
||||
GLSLFLAGS := -mfmt=c
|
||||
|
||||
all: $(SPIRV)
|
||||
|
||||
%.frag.inc: %.frag
|
||||
$(GLSLANG) $(GLSLFLAGS) -o $@ $<
|
||||
|
||||
%.vert.inc: %.vert
|
||||
$(GLSLANG) $(GLSLFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(SPIRV)
|
||||
|
||||
.PHONY: clean
|
@ -1,9 +0,0 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
layout(location = 0) in vec4 vColor;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vColor;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
{0x07230203,0x00010000,0x00080001,0x0000000d,
|
||||
0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,
|
||||
0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0007000f,0x00000004,0x00000004,0x6e69616d,
|
||||
0x00000000,0x00000009,0x0000000b,0x00030010,
|
||||
0x00000004,0x00000007,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,0x00050005,
|
||||
0x00000009,0x67617246,0x6f6c6f43,0x00000072,
|
||||
0x00040005,0x0000000b,0x6c6f4376,0x0000726f,
|
||||
0x00030047,0x00000009,0x00000000,0x00040047,
|
||||
0x00000009,0x0000001e,0x00000000,0x00030047,
|
||||
0x0000000b,0x00000000,0x00040047,0x0000000b,
|
||||
0x0000001e,0x00000000,0x00030047,0x0000000c,
|
||||
0x00000000,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00030016,0x00000006,
|
||||
0x00000020,0x00040017,0x00000007,0x00000006,
|
||||
0x00000004,0x00040020,0x00000008,0x00000003,
|
||||
0x00000007,0x0004003b,0x00000008,0x00000009,
|
||||
0x00000003,0x00040020,0x0000000a,0x00000001,
|
||||
0x00000007,0x0004003b,0x0000000a,0x0000000b,
|
||||
0x00000001,0x00050036,0x00000002,0x00000004,
|
||||
0x00000000,0x00000003,0x000200f8,0x00000005,
|
||||
0x0004003d,0x00000007,0x0000000c,0x0000000b,
|
||||
0x0003003e,0x00000009,0x0000000c,0x000100fd,
|
||||
0x00010038}
|
@ -1,15 +0,0 @@
|
||||
#version 310 es
|
||||
layout(location = 0) in vec4 Position;
|
||||
layout(location = 1) in vec4 Color;
|
||||
layout(location = 0) out vec4 vColor;
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVP * Position;
|
||||
vColor = Color;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
{0x07230203,0x00010000,0x00080001,0x0000001d,
|
||||
0x00000000,0x00020011,0x00000001,0x0006000b,
|
||||
0x00000001,0x4c534c47,0x6474732e,0x3035342e,
|
||||
0x00000000,0x0003000e,0x00000000,0x00000001,
|
||||
0x0009000f,0x00000000,0x00000004,0x6e69616d,
|
||||
0x00000000,0x0000000a,0x00000015,0x0000001a,
|
||||
0x0000001b,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,0x00060005,0x00000008,
|
||||
0x505f6c67,0x65567265,0x78657472,0x00000000,
|
||||
0x00060006,0x00000008,0x00000000,0x505f6c67,
|
||||
0x7469736f,0x006e6f69,0x00070006,0x00000008,
|
||||
0x00000001,0x505f6c67,0x746e696f,0x657a6953,
|
||||
0x00000000,0x00030005,0x0000000a,0x00000000,
|
||||
0x00030005,0x0000000e,0x004f4255,0x00040006,
|
||||
0x0000000e,0x00000000,0x0050564d,0x00030005,
|
||||
0x00000010,0x00000000,0x00050005,0x00000015,
|
||||
0x69736f50,0x6e6f6974,0x00000000,0x00040005,
|
||||
0x0000001a,0x6c6f4376,0x0000726f,0x00040005,
|
||||
0x0000001b,0x6f6c6f43,0x00000072,0x00050048,
|
||||
0x00000008,0x00000000,0x0000000b,0x00000000,
|
||||
0x00050048,0x00000008,0x00000001,0x0000000b,
|
||||
0x00000001,0x00030047,0x00000008,0x00000002,
|
||||
0x00040048,0x0000000e,0x00000000,0x00000005,
|
||||
0x00050048,0x0000000e,0x00000000,0x00000023,
|
||||
0x00000000,0x00050048,0x0000000e,0x00000000,
|
||||
0x00000007,0x00000010,0x00030047,0x0000000e,
|
||||
0x00000002,0x00040047,0x00000010,0x00000022,
|
||||
0x00000000,0x00040047,0x00000010,0x00000021,
|
||||
0x00000000,0x00040047,0x00000015,0x0000001e,
|
||||
0x00000000,0x00040047,0x0000001a,0x0000001e,
|
||||
0x00000000,0x00040047,0x0000001b,0x0000001e,
|
||||
0x00000001,0x00020013,0x00000002,0x00030021,
|
||||
0x00000003,0x00000002,0x00030016,0x00000006,
|
||||
0x00000020,0x00040017,0x00000007,0x00000006,
|
||||
0x00000004,0x0004001e,0x00000008,0x00000007,
|
||||
0x00000006,0x00040020,0x00000009,0x00000003,
|
||||
0x00000008,0x0004003b,0x00000009,0x0000000a,
|
||||
0x00000003,0x00040015,0x0000000b,0x00000020,
|
||||
0x00000001,0x0004002b,0x0000000b,0x0000000c,
|
||||
0x00000000,0x00040018,0x0000000d,0x00000007,
|
||||
0x00000004,0x0003001e,0x0000000e,0x0000000d,
|
||||
0x00040020,0x0000000f,0x00000002,0x0000000e,
|
||||
0x0004003b,0x0000000f,0x00000010,0x00000002,
|
||||
0x00040020,0x00000011,0x00000002,0x0000000d,
|
||||
0x00040020,0x00000014,0x00000001,0x00000007,
|
||||
0x0004003b,0x00000014,0x00000015,0x00000001,
|
||||
0x00040020,0x00000018,0x00000003,0x00000007,
|
||||
0x0004003b,0x00000018,0x0000001a,0x00000003,
|
||||
0x0004003b,0x00000014,0x0000001b,0x00000001,
|
||||
0x00050036,0x00000002,0x00000004,0x00000000,
|
||||
0x00000003,0x000200f8,0x00000005,0x00050041,
|
||||
0x00000011,0x00000012,0x00000010,0x0000000c,
|
||||
0x0004003d,0x0000000d,0x00000013,0x00000012,
|
||||
0x0004003d,0x00000007,0x00000016,0x00000015,
|
||||
0x00050091,0x00000007,0x00000017,0x00000013,
|
||||
0x00000016,0x00050041,0x00000018,0x00000019,
|
||||
0x0000000a,0x0000000c,0x0003003e,0x00000019,
|
||||
0x00000017,0x0004003d,0x00000007,0x0000001c,
|
||||
0x0000001b,0x0003003e,0x0000001a,0x0000001c,
|
||||
0x000100fd,0x00010038}
|
Loading…
x
Reference in New Issue
Block a user