mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +00:00
Vulkan implementation.
This commit is contained in:
parent
0d3c30978d
commit
adbf9fed16
3
.gitignore
vendored
3
.gitignore
vendored
@ -62,6 +62,9 @@ menu/driverspzarch.c
|
||||
/media/shaders_glsl/
|
||||
/obj-w32/
|
||||
|
||||
# Ctags
|
||||
/tags
|
||||
|
||||
# Android
|
||||
/pkg/android/phoenix/obj/
|
||||
/pkg/android/phoenix/assets/
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "deps/glslang/glslang"]
|
||||
path = deps/glslang/glslang
|
||||
url = git://github.com/KhronosGroup/glslang.git
|
6
Makefile
6
Makefile
@ -60,7 +60,9 @@ endif
|
||||
endif
|
||||
|
||||
CFLAGS += -Wall $(OPTIMIZE_FLAG) $(INCLUDE_DIRS) $(DEBUG_FLAG) -I.
|
||||
CXXFLAGS := $(CFLAGS) -std=c++98 -D__STDC_CONSTANT_MACROS
|
||||
|
||||
APPEND_CFLAGS := $(CFLAGS)
|
||||
CXXFLAGS += $(APPEND_CFLAGS) -std=c++11 -D__STDC_CONSTANT_MACROS
|
||||
OBJCFLAGS := $(CFLAGS) -D__STDC_CONSTANT_MACROS
|
||||
|
||||
ifeq ($(CXX_BUILD), 1)
|
||||
@ -127,7 +129,7 @@ $(OBJDIR)/%.o: %.c config.h config.mk
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
$(OBJDIR)/%.o: %.cpp config.h config.mk
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
@ -630,6 +630,9 @@ ifeq ($(HAVE_GL_CONTEXT), 1)
|
||||
ifeq ($(HAVE_EGL), 1)
|
||||
OBJ += gfx/drivers_context/wayland_ctx.o
|
||||
endif
|
||||
ifeq ($(HAVE_VULKAN), 1)
|
||||
OBJ += gfx/drivers_context/wayland_ctx_vulkan.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GLES), 1)
|
||||
@ -694,6 +697,45 @@ ifeq ($(HAVE_SDL2), 1)
|
||||
HAVE_SDL = 0
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_VULKAN), 1)
|
||||
ifeq ($(platform), win)
|
||||
GLSLANG_PLATFORM := Windows
|
||||
else
|
||||
GLSLANG_PLATFORM := Unix
|
||||
endif
|
||||
GLSLANG_SOURCES := \
|
||||
$(wildcard deps/glslang/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/SPIRV/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/glslang/GenericCodeGen/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/OGLCompilersDLL/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/glslang/MachineIndependent/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/glslang/MachineIndependent/preprocessor/*.cpp) \
|
||||
$(wildcard deps/glslang/glslang/glslang/OSDependent/$(GLSLANG_PLATFORM)/*.cpp)
|
||||
|
||||
DEFINES += \
|
||||
-Ideps/glslang/glslang/glslang/OSDependent/$(GLSLANG_PLATFORM) \
|
||||
-Ideps/glslang/glslang \
|
||||
-Ideps/glslang/glslang/glslang/MachineIndependent \
|
||||
-Ideps/glslang/glslang/glslang/Public \
|
||||
-Ideps/glslang/glslang/SPIRV \
|
||||
-Ideps/glslang
|
||||
|
||||
CXXFLAGS += -Wno-switch -Wno-sign-compare -fno-strict-aliasing -Wno-maybe-uninitialized
|
||||
|
||||
GLSLANG_OBJ := $(GLSLANG_SOURCES:.cpp=.o)
|
||||
|
||||
OBJ += gfx/drivers/vulkan.o \
|
||||
gfx/common/vulkan_common.o \
|
||||
gfx/drivers_font/vulkan_raster_font.o \
|
||||
gfx/drivers_shader/shader_vulkan.o \
|
||||
gfx/drivers_shader/glslang_util.o \
|
||||
$(GLSLANG_OBJ)
|
||||
ifeq ($(HAVE_MENU_COMMON), 1)
|
||||
OBJ += menu/drivers_display/menu_display_vulkan.o
|
||||
endif
|
||||
LIBS += -lvulkan -lstdc++
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OMAP), 1)
|
||||
OBJ += gfx/drivers/omap_gfx.o
|
||||
endif
|
||||
|
@ -42,6 +42,8 @@
|
||||
#define COMMAND_EXT_GLSLP 0x0f840c87U
|
||||
#define COMMAND_EXT_CG 0x0059776fU
|
||||
#define COMMAND_EXT_CGP 0x0b8865bfU
|
||||
#define COMMAND_EXT_SLANG 0x105ce63aU
|
||||
#define COMMAND_EXT_SLANGP 0x1bf9adeaU
|
||||
|
||||
struct rarch_cmd
|
||||
{
|
||||
@ -234,6 +236,10 @@ static bool cmd_set_shader(const char *arg)
|
||||
case COMMAND_EXT_CGP:
|
||||
type = RARCH_SHADER_CG;
|
||||
break;
|
||||
case COMMAND_EXT_SLANG:
|
||||
case COMMAND_EXT_SLANGP:
|
||||
type = RARCH_SHADER_SLANG;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
enum
|
||||
{
|
||||
VIDEO_GL = 0,
|
||||
VIDEO_VULKAN,
|
||||
VIDEO_XVIDEO,
|
||||
VIDEO_SDL,
|
||||
VIDEO_SDL2,
|
||||
|
65
cores/libretro-test-vulkan/Makefile
Normal file
65
cores/libretro-test-vulkan/Makefile
Normal file
@ -0,0 +1,65 @@
|
||||
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
|
||||
VULKAN_LIB := -lvulkan
|
||||
else
|
||||
CC = gcc
|
||||
TARGET := $(TARGET_NAME)_libretro.dll
|
||||
SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T -Wl,--no-undefined
|
||||
VULKAN_LIB := -lvulkan
|
||||
CFLAGS += -I..
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
CFLAGS += -std=gnu99
|
||||
OBJECTS := libretro-test.o
|
||||
CFLAGS += -Wall -pedantic $(fpic)
|
||||
LIBS += $(VULKAN_LIB)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
$(CC) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) $(LIBS) -lm $(EXTRA_VULKAN_LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -I../../libretro-common/include $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(TARGET)
|
||||
|
||||
.PHONY: clean
|
||||
|
793
cores/libretro-test-vulkan/libretro-test.c
Normal file
793
cores/libretro-test-vulkan/libretro-test.c
Normal file
@ -0,0 +1,793 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include "../../libretro_vulkan.h"
|
||||
#include "shaders/triangle.vert.inc"
|
||||
#include "shaders/triangle.frag.inc"
|
||||
|
||||
#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;
|
||||
|
||||
#define BASE_WIDTH 320
|
||||
#define BASE_HEIGHT 240
|
||||
#define MAX_SYNC 8
|
||||
|
||||
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;
|
||||
VkCommandPool cmd_pool;
|
||||
|
||||
struct retro_vulkan_image images[MAX_SYNC];
|
||||
VkDeviceMemory image_memory[MAX_SYNC];
|
||||
VkFramebuffer framebuffers[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;
|
||||
|
||||
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 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];
|
||||
vkResetCommandBuffer(cmd, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(cmd, &begin_info);
|
||||
|
||||
VkImageMemoryBarrier prepare_rendering = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
prepare_rendering.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
prepare_rendering.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_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 = BASE_WIDTH;
|
||||
rp_begin.renderArea.extent.height = BASE_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 = BASE_WIDTH;
|
||||
vp.height = BASE_HEIGHT;
|
||||
vp.minDepth = 0.0f;
|
||||
vp.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(cmd, 0, 1, &vp);
|
||||
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
scissor.extent.width = BASE_WIDTH;
|
||||
scissor.extent.height = BASE_HEIGHT;
|
||||
vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||
|
||||
vkCmdSetLineWidth(cmd, 1.0f);
|
||||
vkCmdSetDepthBias(cmd, 0.0f, 0.0f, 0.0f);
|
||||
vkCmdSetDepthBounds(cmd, 0.0f, 1.0f);
|
||||
vkCmdSetStencilCompareMask(cmd, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, 0xff);
|
||||
vkCmdSetStencilWriteMask(cmd, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, 0xff);
|
||||
vkCmdSetStencilReference(cmd, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, 0);
|
||||
static const float blend_const[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
vkCmdSetBlendConstants(cmd, blend_const);
|
||||
|
||||
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 uint8_t *data, size_t size)
|
||||
{
|
||||
VkShaderModuleCreateInfo module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||
VkShaderModule module;
|
||||
module_info.codeSize = size;
|
||||
module_info.pCode = (const uint32_t*)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;
|
||||
|
||||
static const VkDescriptorPoolSize pool_sizes[1] = {
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
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,
|
||||
VK_DYNAMIC_STATE_LINE_WIDTH,
|
||||
VK_DYNAMIC_STATE_DEPTH_BIAS,
|
||||
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS,
|
||||
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
||||
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
|
||||
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
||||
};
|
||||
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 },
|
||||
};
|
||||
|
||||
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shader_stages[0].module = create_shader_module(triangle_vert_spv, triangle_vert_spv_len);
|
||||
shader_stages[0].pName = "main";
|
||||
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shader_stages[1].module = create_shader_module(triangle_frag_spv, triangle_frag_spv_len);
|
||||
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 = BASE_WIDTH;
|
||||
image.extent.height = BASE_HEIGHT;
|
||||
image.extent.depth = 1;
|
||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image.tiling = VK_IMAGE_TILING_LINEAR; /* Workaround. */
|
||||
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, 0);
|
||||
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.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 = BASE_WIDTH;
|
||||
fb_info.height = BASE_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;
|
||||
vkCreateCommandPool(vulkan->device, &pool_info, NULL, &vk.cmd_pool);
|
||||
|
||||
info.commandPool = vk.cmd_pool;
|
||||
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
info.commandBufferCount = vk.num_swapchain_images;
|
||||
vkAllocateCommandBuffers(vulkan->device, &info, vk.cmd);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
vkDestroyPipelineLayout(device, vk.pipeline_layout, NULL);
|
||||
|
||||
vkFreeMemory(device, vk.vbo.memory, NULL);
|
||||
vkDestroyBuffer(device, vk.vbo.buffer, NULL);
|
||||
vkDestroyPipelineCache(device, vk.pipeline_cache, NULL);
|
||||
|
||||
vkFreeCommandBuffers(device, vk.cmd_pool, vk.num_swapchain_images, vk.cmd);
|
||||
vkDestroyCommandPool(device, vk.cmd_pool, NULL);
|
||||
|
||||
memset(&vk, 0, sizeof(vk));
|
||||
}
|
||||
|
||||
void retro_run(void)
|
||||
{
|
||||
/* 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);
|
||||
input_poll_cb();
|
||||
|
||||
vk.index = vulkan->get_sync_index(vulkan->handle);
|
||||
vulkan_test_render();
|
||||
vulkan->set_image(vulkan->handle, &vk.images[vk.index], 0, NULL);
|
||||
vulkan->set_command_buffers(vulkan->handle, 1, &vk.cmd[vk.index]);
|
||||
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;
|
||||
}
|
||||
vulkan_test_init();
|
||||
}
|
||||
|
||||
static void context_destroy(void)
|
||||
{
|
||||
fprintf(stderr, "Context destroy!\n");
|
||||
vulkan_test_deinit();
|
||||
vulkan = NULL;
|
||||
memset(&vk, 0, sizeof(vk));
|
||||
}
|
||||
|
||||
static bool retro_init_hw_context(void)
|
||||
{
|
||||
hw_render.context_type = RETRO_HW_CONTEXT_VULKAN;
|
||||
hw_render.version_major = VK_API_VERSION;
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
5
cores/libretro-test-vulkan/link.T
Normal file
5
cores/libretro-test-vulkan/link.T
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
global: retro_*;
|
||||
local: *;
|
||||
};
|
||||
|
23
cores/libretro-test-vulkan/shaders/Makefile
Normal file
23
cores/libretro-test-vulkan/shaders/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
VERT_SHADERS := $(wildcard *.vert)
|
||||
FRAG_SHADERS := $(wildcard *.frag)
|
||||
SPIRV := $(VERT_SHADERS:.vert=.vert.spv) $(FRAG_SHADERS:.frag=.frag.spv)
|
||||
INCLUDES := $(SPIRV:.spv=.inc)
|
||||
|
||||
GLSLANG := glslangValidator
|
||||
|
||||
all: $(INCLUDES)
|
||||
|
||||
%.frag.spv: %.frag
|
||||
$(GLSLANG) -V -o $@ $<
|
||||
|
||||
%.vert.spv: %.vert
|
||||
$(GLSLANG) -V -o $@ $<
|
||||
|
||||
%.inc: %.spv
|
||||
xxd -i $< $@
|
||||
|
||||
clean:
|
||||
rm -f $(INCLUDES)
|
||||
rm -f $(SPIRV)
|
||||
|
||||
.PHONY: clean
|
9
cores/libretro-test-vulkan/shaders/triangle.frag
Normal file
9
cores/libretro-test-vulkan/shaders/triangle.frag
Normal file
@ -0,0 +1,9 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
layout(location = 0) in vec4 vColor;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vColor;
|
||||
}
|
37
cores/libretro-test-vulkan/shaders/triangle.frag.inc
Normal file
37
cores/libretro-test-vulkan/shaders/triangle.frag.inc
Normal file
@ -0,0 +1,37 @@
|
||||
unsigned char triangle_frag_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x72, 0x61, 0x67,
|
||||
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x76, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00,
|
||||
0x47, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
||||
0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int triangle_frag_spv_len = 400;
|
15
cores/libretro-test-vulkan/shaders/triangle.vert
Normal file
15
cores/libretro-test-vulkan/shaders/triangle.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#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;
|
||||
}
|
94
cores/libretro-test-vulkan/shaders/triangle.vert.inc
Normal file
94
cores/libretro-test-vulkan/shaders/triangle.vert.inc
Normal file
@ -0,0 +1,94 @@
|
||||
unsigned char triangle_vert_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50,
|
||||
0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00,
|
||||
0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x55, 0x42, 0x4f, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4d, 0x56, 0x50, 0x00, 0x05, 0x00, 0x03, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x76, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x1b, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x56,
|
||||
0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00, 0x05, 0x00, 0x06, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x49, 0x44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||
0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
|
||||
0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x03, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int triangle_vert_spv_len = 1088;
|
@ -120,6 +120,8 @@ else
|
||||
CFLAGS += -std=gnu99
|
||||
endif
|
||||
|
||||
CFLAGS += -I../../libretro-common/include
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJECTS)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "../../libretro.h"
|
||||
|
||||
static uint16_t *frame_buf;
|
||||
static uint32_t *frame_buf;
|
||||
static struct retro_log_callback logging;
|
||||
static retro_log_printf_t log_cb;
|
||||
static bool use_audio_cb;
|
||||
@ -27,7 +27,7 @@ static void fallback_log(enum retro_log_level level, const char *fmt, ...)
|
||||
|
||||
void retro_init(void)
|
||||
{
|
||||
frame_buf = calloc(320 * 240, sizeof(uint16_t));
|
||||
frame_buf = calloc(320 * 240, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void retro_deinit(void)
|
||||
@ -278,11 +278,29 @@ static void update_input(void)
|
||||
|
||||
static void render_checkered(void)
|
||||
{
|
||||
uint16_t color_r = 31 << 11;
|
||||
uint16_t color_g = 63 << 5;
|
||||
/* Try rendering straight into VRAM if we can. */
|
||||
uint32_t *buf = NULL;
|
||||
unsigned stride = 0;
|
||||
struct retro_framebuffer fb = {0};
|
||||
fb.width = 320;
|
||||
fb.height = 240;
|
||||
fb.access_flags = RETRO_MEMORY_ACCESS_WRITE;
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) && fb.format == RETRO_PIXEL_FORMAT_XRGB8888)
|
||||
{
|
||||
buf = fb.data;
|
||||
stride = fb.pitch >> 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = frame_buf;
|
||||
stride = 320;
|
||||
}
|
||||
|
||||
uint16_t *line = frame_buf;
|
||||
for (unsigned y = 0; y < 240; y++, line += 320)
|
||||
uint32_t color_r = 0xff << 16;
|
||||
uint32_t color_g = 0xff << 8;
|
||||
|
||||
uint32_t *line = buf;
|
||||
for (unsigned y = 0; y < 240; y++, line += stride)
|
||||
{
|
||||
unsigned index_y = ((y - y_coord) >> 4) & 1;
|
||||
for (unsigned x = 0; x < 320; x++)
|
||||
@ -294,9 +312,9 @@ static void render_checkered(void)
|
||||
|
||||
for (unsigned y = mouse_rel_y - 5; y <= mouse_rel_y + 5; y++)
|
||||
for (unsigned x = mouse_rel_x - 5; x <= mouse_rel_x + 5; x++)
|
||||
frame_buf[y * 320 + x] = 0x1f;
|
||||
buf[y * stride + x] = 0xff;
|
||||
|
||||
video_cb(frame_buf, 320, 240, 320 << 1);
|
||||
video_cb(buf, 320, 240, stride << 2);
|
||||
}
|
||||
|
||||
static void check_variables(void)
|
||||
@ -381,10 +399,10 @@ bool retro_load_game(const struct retro_game_info *info)
|
||||
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
|
||||
|
||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
|
||||
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||
{
|
||||
log_cb(RETRO_LOG_INFO, "RGB565 is not supported.\n");
|
||||
log_cb(RETRO_LOG_INFO, "XRGB8888 is not supported.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
1
deps/glslang/glslang
vendored
Submodule
1
deps/glslang/glslang
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 9d565d9ef802c6984122d182bc1fc477dd5e07ba
|
384
deps/glslang/glslang.cpp
vendored
Normal file
384
deps/glslang/glslang.cpp
vendored
Normal file
@ -0,0 +1,384 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "glslang.hpp"
|
||||
|
||||
#include "ShaderLang.h"
|
||||
#include "GlslangToSpv.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../../general.h"
|
||||
|
||||
using namespace glslang;
|
||||
using namespace std;
|
||||
|
||||
struct SlangProcess
|
||||
{
|
||||
public:
|
||||
SlangProcess();
|
||||
|
||||
TBuiltInResource& GetResources() { return Resources; }
|
||||
~SlangProcess() { FinalizeProcess(); }
|
||||
|
||||
private:
|
||||
TBuiltInResource Resources;
|
||||
};
|
||||
|
||||
SlangProcess::SlangProcess()
|
||||
{
|
||||
InitializeProcess();
|
||||
|
||||
char DefaultConfig[] =
|
||||
"MaxLights 32\n"
|
||||
"MaxClipPlanes 6\n"
|
||||
"MaxTextureUnits 32\n"
|
||||
"MaxTextureCoords 32\n"
|
||||
"MaxVertexAttribs 64\n"
|
||||
"MaxVertexUniformComponents 4096\n"
|
||||
"MaxVaryingFloats 64\n"
|
||||
"MaxVertexTextureImageUnits 32\n"
|
||||
"MaxCombinedTextureImageUnits 80\n"
|
||||
"MaxTextureImageUnits 32\n"
|
||||
"MaxFragmentUniformComponents 4096\n"
|
||||
"MaxDrawBuffers 32\n"
|
||||
"MaxVertexUniformVectors 128\n"
|
||||
"MaxVaryingVectors 8\n"
|
||||
"MaxFragmentUniformVectors 16\n"
|
||||
"MaxVertexOutputVectors 16\n"
|
||||
"MaxFragmentInputVectors 15\n"
|
||||
"MinProgramTexelOffset -8\n"
|
||||
"MaxProgramTexelOffset 7\n"
|
||||
"MaxClipDistances 8\n"
|
||||
"MaxComputeWorkGroupCountX 65535\n"
|
||||
"MaxComputeWorkGroupCountY 65535\n"
|
||||
"MaxComputeWorkGroupCountZ 65535\n"
|
||||
"MaxComputeWorkGroupSizeX 1024\n"
|
||||
"MaxComputeWorkGroupSizeY 1024\n"
|
||||
"MaxComputeWorkGroupSizeZ 64\n"
|
||||
"MaxComputeUniformComponents 1024\n"
|
||||
"MaxComputeTextureImageUnits 16\n"
|
||||
"MaxComputeImageUniforms 8\n"
|
||||
"MaxComputeAtomicCounters 8\n"
|
||||
"MaxComputeAtomicCounterBuffers 1\n"
|
||||
"MaxVaryingComponents 60\n"
|
||||
"MaxVertexOutputComponents 64\n"
|
||||
"MaxGeometryInputComponents 64\n"
|
||||
"MaxGeometryOutputComponents 128\n"
|
||||
"MaxFragmentInputComponents 128\n"
|
||||
"MaxImageUnits 8\n"
|
||||
"MaxCombinedImageUnitsAndFragmentOutputs 8\n"
|
||||
"MaxCombinedShaderOutputResources 8\n"
|
||||
"MaxImageSamples 0\n"
|
||||
"MaxVertexImageUniforms 0\n"
|
||||
"MaxTessControlImageUniforms 0\n"
|
||||
"MaxTessEvaluationImageUniforms 0\n"
|
||||
"MaxGeometryImageUniforms 0\n"
|
||||
"MaxFragmentImageUniforms 8\n"
|
||||
"MaxCombinedImageUniforms 8\n"
|
||||
"MaxGeometryTextureImageUnits 16\n"
|
||||
"MaxGeometryOutputVertices 256\n"
|
||||
"MaxGeometryTotalOutputComponents 1024\n"
|
||||
"MaxGeometryUniformComponents 1024\n"
|
||||
"MaxGeometryVaryingComponents 64\n"
|
||||
"MaxTessControlInputComponents 128\n"
|
||||
"MaxTessControlOutputComponents 128\n"
|
||||
"MaxTessControlTextureImageUnits 16\n"
|
||||
"MaxTessControlUniformComponents 1024\n"
|
||||
"MaxTessControlTotalOutputComponents 4096\n"
|
||||
"MaxTessEvaluationInputComponents 128\n"
|
||||
"MaxTessEvaluationOutputComponents 128\n"
|
||||
"MaxTessEvaluationTextureImageUnits 16\n"
|
||||
"MaxTessEvaluationUniformComponents 1024\n"
|
||||
"MaxTessPatchComponents 120\n"
|
||||
"MaxPatchVertices 32\n"
|
||||
"MaxTessGenLevel 64\n"
|
||||
"MaxViewports 16\n"
|
||||
"MaxVertexAtomicCounters 0\n"
|
||||
"MaxTessControlAtomicCounters 0\n"
|
||||
"MaxTessEvaluationAtomicCounters 0\n"
|
||||
"MaxGeometryAtomicCounters 0\n"
|
||||
"MaxFragmentAtomicCounters 8\n"
|
||||
"MaxCombinedAtomicCounters 8\n"
|
||||
"MaxAtomicCounterBindings 1\n"
|
||||
"MaxVertexAtomicCounterBuffers 0\n"
|
||||
"MaxTessControlAtomicCounterBuffers 0\n"
|
||||
"MaxTessEvaluationAtomicCounterBuffers 0\n"
|
||||
"MaxGeometryAtomicCounterBuffers 0\n"
|
||||
"MaxFragmentAtomicCounterBuffers 1\n"
|
||||
"MaxCombinedAtomicCounterBuffers 1\n"
|
||||
"MaxAtomicCounterBufferSize 16384\n"
|
||||
"MaxTransformFeedbackBuffers 4\n"
|
||||
"MaxTransformFeedbackInterleavedComponents 64\n"
|
||||
"MaxCullDistances 8\n"
|
||||
"MaxCombinedClipAndCullDistances 8\n"
|
||||
"MaxSamples 4\n"
|
||||
|
||||
"nonInductiveForLoops 1\n"
|
||||
"whileLoops 1\n"
|
||||
"doWhileLoops 1\n"
|
||||
"generalUniformIndexing 1\n"
|
||||
"generalAttributeMatrixVectorIndexing 1\n"
|
||||
"generalVaryingIndexing 1\n"
|
||||
"generalSamplerIndexing 1\n"
|
||||
"generalVariableIndexing 1\n"
|
||||
"generalConstantMatrixVectorIndexing 1\n";
|
||||
|
||||
const char *delims = " \t\n\r";
|
||||
const char *token = strtok(DefaultConfig, delims);
|
||||
while (token)
|
||||
{
|
||||
const char *value_str = strtok(0, delims);
|
||||
int value = strtoul(value_str, nullptr, 0);
|
||||
|
||||
if (strcmp(token, "MaxLights") == 0)
|
||||
Resources.maxLights = value;
|
||||
else if (strcmp(token, "MaxClipPlanes") == 0)
|
||||
Resources.maxClipPlanes = value;
|
||||
else if (strcmp(token, "MaxTextureUnits") == 0)
|
||||
Resources.maxTextureUnits = value;
|
||||
else if (strcmp(token, "MaxTextureCoords") == 0)
|
||||
Resources.maxTextureCoords = value;
|
||||
else if (strcmp(token, "MaxVertexAttribs") == 0)
|
||||
Resources.maxVertexAttribs = value;
|
||||
else if (strcmp(token, "MaxVertexUniformComponents") == 0)
|
||||
Resources.maxVertexUniformComponents = value;
|
||||
else if (strcmp(token, "MaxVaryingFloats") == 0)
|
||||
Resources.maxVaryingFloats = value;
|
||||
else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
|
||||
Resources.maxVertexTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
|
||||
Resources.maxCombinedTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTextureImageUnits") == 0)
|
||||
Resources.maxTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
|
||||
Resources.maxFragmentUniformComponents = value;
|
||||
else if (strcmp(token, "MaxDrawBuffers") == 0)
|
||||
Resources.maxDrawBuffers = value;
|
||||
else if (strcmp(token, "MaxVertexUniformVectors") == 0)
|
||||
Resources.maxVertexUniformVectors = value;
|
||||
else if (strcmp(token, "MaxVaryingVectors") == 0)
|
||||
Resources.maxVaryingVectors = value;
|
||||
else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
|
||||
Resources.maxFragmentUniformVectors = value;
|
||||
else if (strcmp(token, "MaxVertexOutputVectors") == 0)
|
||||
Resources.maxVertexOutputVectors = value;
|
||||
else if (strcmp(token, "MaxFragmentInputVectors") == 0)
|
||||
Resources.maxFragmentInputVectors = value;
|
||||
else if (strcmp(token, "MinProgramTexelOffset") == 0)
|
||||
Resources.minProgramTexelOffset = value;
|
||||
else if (strcmp(token, "MaxProgramTexelOffset") == 0)
|
||||
Resources.maxProgramTexelOffset = value;
|
||||
else if (strcmp(token, "MaxClipDistances") == 0)
|
||||
Resources.maxClipDistances = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
|
||||
Resources.maxComputeWorkGroupCountX = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
|
||||
Resources.maxComputeWorkGroupCountY = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
|
||||
Resources.maxComputeWorkGroupCountZ = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
|
||||
Resources.maxComputeWorkGroupSizeX = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
|
||||
Resources.maxComputeWorkGroupSizeY = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
|
||||
Resources.maxComputeWorkGroupSizeZ = value;
|
||||
else if (strcmp(token, "MaxComputeUniformComponents") == 0)
|
||||
Resources.maxComputeUniformComponents = value;
|
||||
else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
|
||||
Resources.maxComputeTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxComputeImageUniforms") == 0)
|
||||
Resources.maxComputeImageUniforms = value;
|
||||
else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
|
||||
Resources.maxComputeAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
|
||||
Resources.maxComputeAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxVaryingComponents") == 0)
|
||||
Resources.maxVaryingComponents = value;
|
||||
else if (strcmp(token, "MaxVertexOutputComponents") == 0)
|
||||
Resources.maxVertexOutputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryInputComponents") == 0)
|
||||
Resources.maxGeometryInputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
|
||||
Resources.maxGeometryOutputComponents = value;
|
||||
else if (strcmp(token, "MaxFragmentInputComponents") == 0)
|
||||
Resources.maxFragmentInputComponents = value;
|
||||
else if (strcmp(token, "MaxImageUnits") == 0)
|
||||
Resources.maxImageUnits = value;
|
||||
else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
|
||||
else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
|
||||
Resources.maxCombinedShaderOutputResources = value;
|
||||
else if (strcmp(token, "MaxImageSamples") == 0)
|
||||
Resources.maxImageSamples = value;
|
||||
else if (strcmp(token, "MaxVertexImageUniforms") == 0)
|
||||
Resources.maxVertexImageUniforms = value;
|
||||
else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
|
||||
Resources.maxTessControlImageUniforms = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
|
||||
Resources.maxTessEvaluationImageUniforms = value;
|
||||
else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
|
||||
Resources.maxGeometryImageUniforms = value;
|
||||
else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
|
||||
Resources.maxFragmentImageUniforms = value;
|
||||
else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
|
||||
Resources.maxCombinedImageUniforms = value;
|
||||
else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
|
||||
Resources.maxGeometryTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
|
||||
Resources.maxGeometryOutputVertices = value;
|
||||
else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
|
||||
Resources.maxGeometryTotalOutputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
|
||||
Resources.maxGeometryUniformComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
|
||||
Resources.maxGeometryVaryingComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlInputComponents") == 0)
|
||||
Resources.maxTessControlInputComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
|
||||
Resources.maxTessControlOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
|
||||
Resources.maxTessControlTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
|
||||
Resources.maxTessControlUniformComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
|
||||
Resources.maxTessControlTotalOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
|
||||
Resources.maxTessEvaluationInputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
|
||||
Resources.maxTessEvaluationOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
|
||||
Resources.maxTessEvaluationTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
|
||||
Resources.maxTessEvaluationUniformComponents = value;
|
||||
else if (strcmp(token, "MaxTessPatchComponents") == 0)
|
||||
Resources.maxTessPatchComponents = value;
|
||||
else if (strcmp(token, "MaxPatchVertices") == 0)
|
||||
Resources.maxPatchVertices = value;
|
||||
else if (strcmp(token, "MaxTessGenLevel") == 0)
|
||||
Resources.maxTessGenLevel = value;
|
||||
else if (strcmp(token, "MaxViewports") == 0)
|
||||
Resources.maxViewports = value;
|
||||
else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
|
||||
Resources.maxVertexAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
|
||||
Resources.maxTessControlAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
|
||||
Resources.maxTessEvaluationAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
|
||||
Resources.maxGeometryAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
|
||||
Resources.maxFragmentAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
|
||||
Resources.maxCombinedAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
|
||||
Resources.maxAtomicCounterBindings = value;
|
||||
else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
|
||||
Resources.maxVertexAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
|
||||
Resources.maxTessControlAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
|
||||
Resources.maxTessEvaluationAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
|
||||
Resources.maxGeometryAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
|
||||
Resources.maxFragmentAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
|
||||
Resources.maxCombinedAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
|
||||
Resources.maxAtomicCounterBufferSize = value;
|
||||
else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
|
||||
Resources.maxTransformFeedbackBuffers = value;
|
||||
else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
|
||||
Resources.maxTransformFeedbackInterleavedComponents = value;
|
||||
else if (strcmp(token, "MaxCullDistances") == 0)
|
||||
Resources.maxCullDistances = value;
|
||||
else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
|
||||
Resources.maxCombinedClipAndCullDistances = value;
|
||||
else if (strcmp(token, "MaxSamples") == 0)
|
||||
Resources.maxSamples = value;
|
||||
else if (strcmp(token, "nonInductiveForLoops") == 0)
|
||||
Resources.limits.nonInductiveForLoops = (value != 0);
|
||||
else if (strcmp(token, "whileLoops") == 0)
|
||||
Resources.limits.whileLoops = (value != 0);
|
||||
else if (strcmp(token, "doWhileLoops") == 0)
|
||||
Resources.limits.doWhileLoops = (value != 0);
|
||||
else if (strcmp(token, "generalUniformIndexing") == 0)
|
||||
Resources.limits.generalUniformIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
|
||||
Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalVaryingIndexing") == 0)
|
||||
Resources.limits.generalVaryingIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalSamplerIndexing") == 0)
|
||||
Resources.limits.generalSamplerIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalVariableIndexing") == 0)
|
||||
Resources.limits.generalVariableIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
|
||||
Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
|
||||
|
||||
token = strtok(0, delims);
|
||||
}
|
||||
}
|
||||
|
||||
bool glslang::compile_spirv(const string &source, Stage stage, std::vector<uint32_t> *spirv)
|
||||
{
|
||||
static SlangProcess process;
|
||||
|
||||
TProgram program;
|
||||
EShLanguage language;
|
||||
switch (stage)
|
||||
{
|
||||
case StageVertex: language = EShLangVertex; break;
|
||||
case StageTessControl: language = EShLangTessControl; break;
|
||||
case StageTessEvaluation: language = EShLangTessEvaluation; break;
|
||||
case StageGeometry: language = EShLangGeometry; break;
|
||||
case StageFragment: language = EShLangFragment; break;
|
||||
case StageCompute: language = EShLangCompute; break;
|
||||
default: return false;
|
||||
}
|
||||
TShader shader(language);
|
||||
|
||||
const char *src = source.c_str();
|
||||
shader.setStrings(&src, 1);
|
||||
|
||||
string msg;
|
||||
if (!shader.preprocess(&process.GetResources(), 100, ENoProfile, false, false, EShMsgDefault, &msg, TShader::ForbidInclude()))
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!shader.parse(&process.GetResources(), 100, false, EShMsgDefault))
|
||||
{
|
||||
RARCH_ERR("%s\n", shader.getInfoLog());
|
||||
RARCH_ERR("%s\n", shader.getInfoDebugLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
program.addShader(&shader);
|
||||
|
||||
if (!program.link(EShMsgDefault))
|
||||
{
|
||||
RARCH_ERR("%s\n", program.getInfoLog());
|
||||
RARCH_ERR("%s\n", program.getInfoDebugLog());
|
||||
return false;
|
||||
}
|
||||
|
||||
GlslangToSpv(*program.getIntermediate(language), *spirv);
|
||||
return true;
|
||||
}
|
||||
|
24
deps/glslang/glslang.hpp
vendored
Normal file
24
deps/glslang/glslang.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef GLSLANG_COMPILER_HPP
|
||||
#define GLSLANG_COMPILER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace glslang
|
||||
{
|
||||
enum Stage
|
||||
{
|
||||
StageVertex = 0,
|
||||
StageTessControl,
|
||||
StageTessEvaluation,
|
||||
StageGeometry,
|
||||
StageFragment,
|
||||
StageCompute
|
||||
};
|
||||
|
||||
bool compile_spirv(const std::string &source, Stage stage, std::vector<uint32_t> *spirv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
6805
deps/glslang/glslang_tab.cpp
vendored
Normal file
6805
deps/glslang/glslang_tab.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
316
deps/glslang/glslang_tab.cpp.h
vendored
Normal file
316
deps/glslang/glslang_tab.cpp.h
vendored
Normal file
@ -0,0 +1,316 @@
|
||||
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
#ifndef YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
|
||||
# define YY_YY_GLSLANG_TAB_CPP_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 1
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token type. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
ATTRIBUTE = 258,
|
||||
VARYING = 259,
|
||||
CONST = 260,
|
||||
BOOL = 261,
|
||||
FLOAT = 262,
|
||||
DOUBLE = 263,
|
||||
INT = 264,
|
||||
UINT = 265,
|
||||
BREAK = 266,
|
||||
CONTINUE = 267,
|
||||
DO = 268,
|
||||
ELSE = 269,
|
||||
FOR = 270,
|
||||
IF = 271,
|
||||
DISCARD = 272,
|
||||
RETURN = 273,
|
||||
SWITCH = 274,
|
||||
CASE = 275,
|
||||
DEFAULT = 276,
|
||||
SUBROUTINE = 277,
|
||||
BVEC2 = 278,
|
||||
BVEC3 = 279,
|
||||
BVEC4 = 280,
|
||||
IVEC2 = 281,
|
||||
IVEC3 = 282,
|
||||
IVEC4 = 283,
|
||||
UVEC2 = 284,
|
||||
UVEC3 = 285,
|
||||
UVEC4 = 286,
|
||||
VEC2 = 287,
|
||||
VEC3 = 288,
|
||||
VEC4 = 289,
|
||||
MAT2 = 290,
|
||||
MAT3 = 291,
|
||||
MAT4 = 292,
|
||||
CENTROID = 293,
|
||||
IN = 294,
|
||||
OUT = 295,
|
||||
INOUT = 296,
|
||||
UNIFORM = 297,
|
||||
PATCH = 298,
|
||||
SAMPLE = 299,
|
||||
BUFFER = 300,
|
||||
SHARED = 301,
|
||||
COHERENT = 302,
|
||||
VOLATILE = 303,
|
||||
RESTRICT = 304,
|
||||
READONLY = 305,
|
||||
WRITEONLY = 306,
|
||||
DVEC2 = 307,
|
||||
DVEC3 = 308,
|
||||
DVEC4 = 309,
|
||||
DMAT2 = 310,
|
||||
DMAT3 = 311,
|
||||
DMAT4 = 312,
|
||||
NOPERSPECTIVE = 313,
|
||||
FLAT = 314,
|
||||
SMOOTH = 315,
|
||||
LAYOUT = 316,
|
||||
MAT2X2 = 317,
|
||||
MAT2X3 = 318,
|
||||
MAT2X4 = 319,
|
||||
MAT3X2 = 320,
|
||||
MAT3X3 = 321,
|
||||
MAT3X4 = 322,
|
||||
MAT4X2 = 323,
|
||||
MAT4X3 = 324,
|
||||
MAT4X4 = 325,
|
||||
DMAT2X2 = 326,
|
||||
DMAT2X3 = 327,
|
||||
DMAT2X4 = 328,
|
||||
DMAT3X2 = 329,
|
||||
DMAT3X3 = 330,
|
||||
DMAT3X4 = 331,
|
||||
DMAT4X2 = 332,
|
||||
DMAT4X3 = 333,
|
||||
DMAT4X4 = 334,
|
||||
ATOMIC_UINT = 335,
|
||||
SAMPLER1D = 336,
|
||||
SAMPLER2D = 337,
|
||||
SAMPLER3D = 338,
|
||||
SAMPLERCUBE = 339,
|
||||
SAMPLER1DSHADOW = 340,
|
||||
SAMPLER2DSHADOW = 341,
|
||||
SAMPLERCUBESHADOW = 342,
|
||||
SAMPLER1DARRAY = 343,
|
||||
SAMPLER2DARRAY = 344,
|
||||
SAMPLER1DARRAYSHADOW = 345,
|
||||
SAMPLER2DARRAYSHADOW = 346,
|
||||
ISAMPLER1D = 347,
|
||||
ISAMPLER2D = 348,
|
||||
ISAMPLER3D = 349,
|
||||
ISAMPLERCUBE = 350,
|
||||
ISAMPLER1DARRAY = 351,
|
||||
ISAMPLER2DARRAY = 352,
|
||||
USAMPLER1D = 353,
|
||||
USAMPLER2D = 354,
|
||||
USAMPLER3D = 355,
|
||||
USAMPLERCUBE = 356,
|
||||
USAMPLER1DARRAY = 357,
|
||||
USAMPLER2DARRAY = 358,
|
||||
SAMPLER2DRECT = 359,
|
||||
SAMPLER2DRECTSHADOW = 360,
|
||||
ISAMPLER2DRECT = 361,
|
||||
USAMPLER2DRECT = 362,
|
||||
SAMPLERBUFFER = 363,
|
||||
ISAMPLERBUFFER = 364,
|
||||
USAMPLERBUFFER = 365,
|
||||
SAMPLERCUBEARRAY = 366,
|
||||
SAMPLERCUBEARRAYSHADOW = 367,
|
||||
ISAMPLERCUBEARRAY = 368,
|
||||
USAMPLERCUBEARRAY = 369,
|
||||
SAMPLER2DMS = 370,
|
||||
ISAMPLER2DMS = 371,
|
||||
USAMPLER2DMS = 372,
|
||||
SAMPLER2DMSARRAY = 373,
|
||||
ISAMPLER2DMSARRAY = 374,
|
||||
USAMPLER2DMSARRAY = 375,
|
||||
SAMPLEREXTERNALOES = 376,
|
||||
IMAGE1D = 377,
|
||||
IIMAGE1D = 378,
|
||||
UIMAGE1D = 379,
|
||||
IMAGE2D = 380,
|
||||
IIMAGE2D = 381,
|
||||
UIMAGE2D = 382,
|
||||
IMAGE3D = 383,
|
||||
IIMAGE3D = 384,
|
||||
UIMAGE3D = 385,
|
||||
IMAGE2DRECT = 386,
|
||||
IIMAGE2DRECT = 387,
|
||||
UIMAGE2DRECT = 388,
|
||||
IMAGECUBE = 389,
|
||||
IIMAGECUBE = 390,
|
||||
UIMAGECUBE = 391,
|
||||
IMAGEBUFFER = 392,
|
||||
IIMAGEBUFFER = 393,
|
||||
UIMAGEBUFFER = 394,
|
||||
IMAGE1DARRAY = 395,
|
||||
IIMAGE1DARRAY = 396,
|
||||
UIMAGE1DARRAY = 397,
|
||||
IMAGE2DARRAY = 398,
|
||||
IIMAGE2DARRAY = 399,
|
||||
UIMAGE2DARRAY = 400,
|
||||
IMAGECUBEARRAY = 401,
|
||||
IIMAGECUBEARRAY = 402,
|
||||
UIMAGECUBEARRAY = 403,
|
||||
IMAGE2DMS = 404,
|
||||
IIMAGE2DMS = 405,
|
||||
UIMAGE2DMS = 406,
|
||||
IMAGE2DMSARRAY = 407,
|
||||
IIMAGE2DMSARRAY = 408,
|
||||
UIMAGE2DMSARRAY = 409,
|
||||
STRUCT = 410,
|
||||
VOID = 411,
|
||||
WHILE = 412,
|
||||
IDENTIFIER = 413,
|
||||
TYPE_NAME = 414,
|
||||
FLOATCONSTANT = 415,
|
||||
DOUBLECONSTANT = 416,
|
||||
INTCONSTANT = 417,
|
||||
UINTCONSTANT = 418,
|
||||
BOOLCONSTANT = 419,
|
||||
LEFT_OP = 420,
|
||||
RIGHT_OP = 421,
|
||||
INC_OP = 422,
|
||||
DEC_OP = 423,
|
||||
LE_OP = 424,
|
||||
GE_OP = 425,
|
||||
EQ_OP = 426,
|
||||
NE_OP = 427,
|
||||
AND_OP = 428,
|
||||
OR_OP = 429,
|
||||
XOR_OP = 430,
|
||||
MUL_ASSIGN = 431,
|
||||
DIV_ASSIGN = 432,
|
||||
ADD_ASSIGN = 433,
|
||||
MOD_ASSIGN = 434,
|
||||
LEFT_ASSIGN = 435,
|
||||
RIGHT_ASSIGN = 436,
|
||||
AND_ASSIGN = 437,
|
||||
XOR_ASSIGN = 438,
|
||||
OR_ASSIGN = 439,
|
||||
SUB_ASSIGN = 440,
|
||||
LEFT_PAREN = 441,
|
||||
RIGHT_PAREN = 442,
|
||||
LEFT_BRACKET = 443,
|
||||
RIGHT_BRACKET = 444,
|
||||
LEFT_BRACE = 445,
|
||||
RIGHT_BRACE = 446,
|
||||
DOT = 447,
|
||||
COMMA = 448,
|
||||
COLON = 449,
|
||||
EQUAL = 450,
|
||||
SEMICOLON = 451,
|
||||
BANG = 452,
|
||||
DASH = 453,
|
||||
TILDE = 454,
|
||||
PLUS = 455,
|
||||
STAR = 456,
|
||||
SLASH = 457,
|
||||
PERCENT = 458,
|
||||
LEFT_ANGLE = 459,
|
||||
RIGHT_ANGLE = 460,
|
||||
VERTICAL_BAR = 461,
|
||||
CARET = 462,
|
||||
AMPERSAND = 463,
|
||||
QUESTION = 464,
|
||||
INVARIANT = 465,
|
||||
PRECISE = 466,
|
||||
HIGH_PRECISION = 467,
|
||||
MEDIUM_PRECISION = 468,
|
||||
LOW_PRECISION = 469,
|
||||
PRECISION = 470,
|
||||
PACKED = 471,
|
||||
RESOURCE = 472,
|
||||
SUPERP = 473
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 66 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
union {
|
||||
glslang::TString *string;
|
||||
int i;
|
||||
unsigned int u;
|
||||
bool b;
|
||||
double d;
|
||||
};
|
||||
glslang::TSymbol* symbol;
|
||||
} lex;
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
glslang::TOperator op;
|
||||
union {
|
||||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
glslang::TFunction* function;
|
||||
glslang::TParameter param;
|
||||
glslang::TTypeLoc typeLine;
|
||||
glslang::TTypeList* typeList;
|
||||
glslang::TArraySizes* arraySizes;
|
||||
glslang::TIdentifierList* identifierList;
|
||||
};
|
||||
} interm;
|
||||
|
||||
#line 305 "glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int yyparse (glslang::TParseContext* pParseContext);
|
||||
|
||||
#endif /* !YY_YY_GLSLANG_TAB_CPP_H_INCLUDED */
|
2
deps/glslang/update_yacc.sh
vendored
Executable file
2
deps/glslang/update_yacc.sh
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
bison --defines=glslang_tab.cpp.h -o glslang_tab.cpp -t glslang/glslang/MachineIndependent/glslang.y
|
@ -55,7 +55,7 @@ struct string_list *dir_list_new_special(const char *input_dir,
|
||||
break;
|
||||
case DIR_LIST_SHADERS:
|
||||
dir = settings->video.shader_dir;
|
||||
exts = "cg|cgp|glsl|glslp";
|
||||
exts = "cg|cgp|glsl|glslp|slang|slangp";
|
||||
break;
|
||||
case DIR_LIST_COLLECTIONS:
|
||||
dir = settings->playlist_directory;
|
||||
|
15
dynamic.c
15
dynamic.c
@ -878,6 +878,16 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
RARCH_LOG("Requesting no HW context.\n");
|
||||
break;
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
RARCH_LOG("Requesting Vulkan context.\n");
|
||||
break;
|
||||
#else
|
||||
case RETRO_HW_CONTEXT_VULKAN:
|
||||
RARCH_ERR("Requesting Vulkan context, but RetroArch is not compiled against Vulkan. Cannot use HW context.\n");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_OPENGLES2)
|
||||
case RETRO_HW_CONTEXT_OPENGLES2:
|
||||
#if defined(HAVE_OPENGLES3)
|
||||
@ -1213,6 +1223,11 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
RARCH_DISPLAY_CTL_GET_CURRENT_SOFTWARE_FRAMEBUFFER,
|
||||
(struct retro_framebuffer*)data);
|
||||
|
||||
case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE:
|
||||
return video_driver_ctl(
|
||||
RARCH_DISPLAY_CTL_GET_HW_RENDER_INTERFACE,
|
||||
(const struct retro_hw_render_interface**)data);
|
||||
|
||||
/* Private extensions for internal use, not part of libretro API. */
|
||||
/* None yet. */
|
||||
|
||||
|
756
gfx/common/vulkan_common.c
Normal file
756
gfx/common/vulkan_common.c
Normal file
@ -0,0 +1,756 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "vulkan_common.h"
|
||||
#include <retro_assert.h>
|
||||
|
||||
uint32_t vulkan_find_memory_type(const VkPhysicalDeviceMemoryProperties *mem_props,
|
||||
uint32_t device_reqs, uint32_t host_reqs)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < VK_MAX_MEMORY_TYPES; i++)
|
||||
{
|
||||
if ((device_reqs & (1u << i)) &&
|
||||
(mem_props->memoryTypes[i].propertyFlags & host_reqs) == host_reqs)
|
||||
return i;
|
||||
}
|
||||
|
||||
RARCH_ERR("[Vulkan]: Failed to find valid memory type. This should never happen.");
|
||||
abort();
|
||||
}
|
||||
|
||||
uint32_t vulkan_find_memory_type_fallback(const VkPhysicalDeviceMemoryProperties *mem_props,
|
||||
uint32_t device_reqs, uint32_t host_reqs)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < VK_MAX_MEMORY_TYPES; i++)
|
||||
{
|
||||
if ((device_reqs & (1u << i)) &&
|
||||
(mem_props->memoryTypes[i].propertyFlags & host_reqs) == host_reqs)
|
||||
return i;
|
||||
}
|
||||
|
||||
return vulkan_find_memory_type(mem_props, device_reqs, 0);
|
||||
}
|
||||
|
||||
void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *texture)
|
||||
{
|
||||
vkMapMemory(device, texture->memory, texture->offset, texture->size, 0, &texture->mapped);
|
||||
}
|
||||
|
||||
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
||||
static VkImage vk_images[4 * 1024];
|
||||
static unsigned vk_count;
|
||||
|
||||
void vulkan_log_textures(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < vk_count; i++)
|
||||
{
|
||||
RARCH_WARN("[Vulkan]: Found leaked texture %llu.\n",
|
||||
(unsigned long long)vk_images[i]);
|
||||
}
|
||||
vk_count = 0;
|
||||
}
|
||||
|
||||
static unsigned track_seq;
|
||||
static void vulkan_track_alloc(VkImage image)
|
||||
{
|
||||
vk_images[vk_count++] = image;
|
||||
RARCH_LOG("[Vulkan]: Alloc %llu (%u).\n", (unsigned long long)image, track_seq);
|
||||
track_seq++;
|
||||
}
|
||||
|
||||
static void vulkan_track_dealloc(VkImage image)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < vk_count; i++)
|
||||
{
|
||||
if (image == vk_images[i])
|
||||
{
|
||||
vk_count--;
|
||||
memmove(vk_images + i, vk_images + 1 + i, sizeof(VkImage) * (vk_count - i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
retro_assert(0 && "Couldn't find VkImage in dealloc!");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
struct vk_texture *old,
|
||||
unsigned width, unsigned height,
|
||||
VkFormat format,
|
||||
const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type)
|
||||
{
|
||||
/* TODO: Evaluate how we should do texture uploads on discrete cards optimally.
|
||||
* For integrated GPUs, using linear texture is highly desirable to avoid extra copies, but
|
||||
* we might need to take a DMA transfer with block interleave on desktop GPUs.
|
||||
*
|
||||
* Also, Vulkan drivers are not required to support sampling from linear textures
|
||||
* (only TRANSFER), but seems to work fine on GPUs I've tested so far. */
|
||||
|
||||
VkDevice device = vk->context->device;
|
||||
struct vk_texture tex;
|
||||
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
|
||||
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
VkMemoryRequirements mem_reqs;
|
||||
VkSubresourceLayout layout;
|
||||
|
||||
if (type == VULKAN_TEXTURE_STATIC && !initial)
|
||||
retro_assert(0 && "Static textures must have initial data.\n");
|
||||
|
||||
memset(&tex, 0, sizeof(tex));
|
||||
|
||||
info.imageType = VK_IMAGE_TYPE_2D;
|
||||
info.format = format;
|
||||
info.extent.width = width;
|
||||
info.extent.height = height;
|
||||
info.extent.depth = 1;
|
||||
info.mipLevels = 1;
|
||||
info.arrayLayers = 1;
|
||||
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
info.tiling = type != VULKAN_TEXTURE_STATIC ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
|
||||
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
if (type == VULKAN_TEXTURE_STATIC)
|
||||
info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
if (type == VULKAN_TEXTURE_READBACK)
|
||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
/* We'll transition this on first use for streamed textures. */
|
||||
info.initialLayout = type == VULKAN_TEXTURE_STREAMED ?
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED :
|
||||
VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
vkCreateImage(device, &info, NULL, &tex.image);
|
||||
#if 0
|
||||
vulkan_track_alloc(tex.image);
|
||||
#endif
|
||||
|
||||
vkGetImageMemoryRequirements(device, tex.image, &mem_reqs);
|
||||
|
||||
alloc.allocationSize = mem_reqs.size;
|
||||
|
||||
if (type == VULKAN_TEXTURE_STATIC)
|
||||
{
|
||||
alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties,
|
||||
mem_reqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This must exist. */
|
||||
alloc.memoryTypeIndex = vulkan_find_memory_type(&vk->context->memory_properties,
|
||||
mem_reqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
|
||||
/* We're not reusing the objects themselves. */
|
||||
if (old && old->view != VK_NULL_HANDLE)
|
||||
vkDestroyImageView(vk->context->device, old->view, NULL);
|
||||
if (old && old->image != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyImage(vk->context->device, old->image, NULL);
|
||||
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
||||
vulkan_track_dealloc(old->image);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We can pilfer the old memory and move it over to the new texture. */
|
||||
if (old &&
|
||||
old->memory_size >= mem_reqs.size &&
|
||||
old->memory_type == alloc.memoryTypeIndex)
|
||||
{
|
||||
tex.memory = old->memory;
|
||||
tex.memory_size = old->memory_size;
|
||||
tex.memory_type = old->memory_type;
|
||||
|
||||
if (old->mapped)
|
||||
vkUnmapMemory(device, old->memory);
|
||||
old->memory = VK_NULL_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
vkAllocateMemory(device, &alloc, NULL, &tex.memory);
|
||||
tex.memory_size = alloc.allocationSize;
|
||||
tex.memory_type = alloc.memoryTypeIndex;
|
||||
}
|
||||
|
||||
if (old)
|
||||
{
|
||||
if (old->memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(device, old->memory, NULL);
|
||||
memset(old, 0, sizeof(*old));
|
||||
}
|
||||
|
||||
vkBindImageMemory(device, tex.image, tex.memory, 0);
|
||||
|
||||
view.image = tex.image;
|
||||
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view.format = format;
|
||||
if (swizzle)
|
||||
view.components = *swizzle;
|
||||
else
|
||||
{
|
||||
view.components.r = VK_COMPONENT_SWIZZLE_R;
|
||||
view.components.g = VK_COMPONENT_SWIZZLE_G;
|
||||
view.components.b = VK_COMPONENT_SWIZZLE_B;
|
||||
view.components.a = VK_COMPONENT_SWIZZLE_A;
|
||||
}
|
||||
view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
view.subresourceRange.levelCount = 1;
|
||||
view.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCreateImageView(device, &view, NULL, &tex.view);
|
||||
|
||||
vkGetImageSubresourceLayout(device, tex.image, &subresource, &layout);
|
||||
tex.stride = layout.rowPitch;
|
||||
tex.offset = layout.offset;
|
||||
tex.size = layout.size;
|
||||
tex.layout = info.initialLayout;
|
||||
|
||||
tex.width = width;
|
||||
tex.height = height;
|
||||
tex.format = format;
|
||||
|
||||
if (initial && type == VULKAN_TEXTURE_STREAMED)
|
||||
{
|
||||
unsigned bpp = vulkan_format_to_bpp(tex.format);
|
||||
unsigned stride = tex.width * bpp;
|
||||
unsigned x, y;
|
||||
uint8_t *dst;
|
||||
const uint8_t *src;
|
||||
void *ptr;
|
||||
|
||||
vkMapMemory(device, tex.memory, tex.offset, tex.size, 0, &ptr);
|
||||
|
||||
dst = (uint8_t*)ptr;
|
||||
src = (const uint8_t*)initial;
|
||||
for (y = 0; y < tex.height; y++, dst += tex.stride, src += stride)
|
||||
memcpy(dst, src, width * bpp);
|
||||
|
||||
vkUnmapMemory(device, tex.memory);
|
||||
}
|
||||
else if (initial && type == VULKAN_TEXTURE_STATIC)
|
||||
{
|
||||
VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
VkImageCopy region;
|
||||
|
||||
VkCommandBuffer staging;
|
||||
unsigned bpp = vulkan_format_to_bpp(tex.format);
|
||||
struct vk_texture tmp = vulkan_create_texture(vk, NULL,
|
||||
width, height, format, initial, NULL, VULKAN_TEXTURE_STREAMED);
|
||||
|
||||
info.commandPool = vk->staging_pool;
|
||||
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
info.commandBufferCount = 1;
|
||||
vkAllocateCommandBuffers(vk->context->device, &info, &staging);
|
||||
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(staging, &begin_info);
|
||||
|
||||
vulkan_image_layout_transition(vk, staging, tmp.image,
|
||||
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
||||
vulkan_image_layout_transition(vk, staging, tex.image,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
||||
memset(®ion, 0, sizeof(region));
|
||||
region.extent.width = width;
|
||||
region.extent.height = height;
|
||||
region.extent.depth = 1;
|
||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.srcSubresource.layerCount = 1;
|
||||
region.dstSubresource = region.srcSubresource;
|
||||
|
||||
vkCmdCopyImage(staging,
|
||||
tmp.image, VK_IMAGE_LAYOUT_GENERAL,
|
||||
tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ®ion);
|
||||
|
||||
vulkan_image_layout_transition(vk, staging, tex.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
||||
vkEndCommandBuffer(staging);
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &staging;
|
||||
|
||||
slock_lock(vk->context->queue_lock);
|
||||
vkQueueSubmit(vk->context->queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
/* TODO: Very crude, but texture uploads only happen during init,
|
||||
* so waiting for GPU to complete transfer and blocking isn't a big deal. */
|
||||
vkQueueWaitIdle(vk->context->queue);
|
||||
slock_unlock(vk->context->queue_lock);
|
||||
|
||||
vkFreeCommandBuffers(vk->context->device, vk->staging_pool, 1, &staging);
|
||||
vulkan_destroy_texture(vk->context->device, &tmp);
|
||||
tex.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
||||
void vulkan_destroy_texture(VkDevice device, struct vk_texture *tex)
|
||||
{
|
||||
if (tex->mapped)
|
||||
vkUnmapMemory(device, tex->memory);
|
||||
vkFreeMemory(device, tex->memory, NULL);
|
||||
vkDestroyImageView(device, tex->view, NULL);
|
||||
vkDestroyImage(device, tex->image, NULL);
|
||||
#ifdef VULKAN_DEBUG_TEXTURE_ALLOC
|
||||
vulkan_track_dealloc(tex->image);
|
||||
#endif
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
}
|
||||
|
||||
static void vulkan_write_quad_descriptors(VkDevice device,
|
||||
VkDescriptorSet set,
|
||||
const struct vk_texture *texture,
|
||||
VkSampler sampler)
|
||||
{
|
||||
VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
|
||||
VkDescriptorImageInfo image_info;
|
||||
|
||||
image_info.sampler = sampler;
|
||||
image_info.imageView = texture->view;
|
||||
image_info.imageLayout = texture->layout;
|
||||
|
||||
write.dstSet = set;
|
||||
write.dstBinding = 0;
|
||||
write.descriptorCount = 1;
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
write.pImageInfo = &image_info;
|
||||
|
||||
vkUpdateDescriptorSets(device, 1, &write, 0, NULL);
|
||||
}
|
||||
|
||||
void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture)
|
||||
{
|
||||
/* Transition to GENERAL layout for linear streamed textures.
|
||||
* We're using linear textures here, so only GENERAL layout is supported.
|
||||
*/
|
||||
if (texture->layout == VK_IMAGE_LAYOUT_PREINITIALIZED)
|
||||
{
|
||||
vulkan_image_layout_transition(vk, vk->cmd, texture->image,
|
||||
texture->layout, VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
texture->layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_check_dynamic_state(vk_t *vk)
|
||||
{
|
||||
if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT)
|
||||
{
|
||||
const VkRect2D sci = {{ vk->vp.x, vk->vp.y }, { vk->vp.width, vk->vp.height }};
|
||||
vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp);
|
||||
vkCmdSetScissor(vk->cmd, 0, 1, &sci);
|
||||
|
||||
vk->tracker.dirty &= ~VULKAN_DIRTY_DYNAMIC_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call)
|
||||
{
|
||||
vulkan_transition_texture(vk, call->texture);
|
||||
|
||||
if (call->pipeline != vk->tracker.pipeline)
|
||||
{
|
||||
vkCmdBindPipeline(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, call->pipeline);
|
||||
vk->tracker.pipeline = call->pipeline;
|
||||
|
||||
/* Changing pipeline invalidates dynamic state. */
|
||||
vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT;
|
||||
}
|
||||
|
||||
vulkan_check_dynamic_state(vk);
|
||||
|
||||
/* Upload descriptors */
|
||||
{
|
||||
struct vk_draw_uniform ubo;
|
||||
VkDescriptorSet set;
|
||||
|
||||
ubo.mvp = *call->mvp;
|
||||
ubo.texsize[0] = call->texture->width;
|
||||
ubo.texsize[1] = call->texture->height;
|
||||
ubo.texsize[2] = 1.0f / call->texture->width;
|
||||
ubo.texsize[3] = 1.0f / call->texture->height;
|
||||
|
||||
if (call->texture->view != vk->tracker.view || call->sampler != vk->tracker.sampler)
|
||||
{
|
||||
set = vulkan_descriptor_manager_alloc(vk->context->device, &vk->chain->descriptor_manager);
|
||||
vulkan_write_quad_descriptors(vk->context->device,
|
||||
set,
|
||||
call->texture,
|
||||
call->sampler);
|
||||
|
||||
vkCmdBindDescriptorSets(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
vk->pipelines.layout, 0,
|
||||
1, &set, 0, NULL);
|
||||
|
||||
vk->tracker.view = call->texture->view;
|
||||
vk->tracker.sampler = call->sampler;
|
||||
}
|
||||
|
||||
vkCmdPushConstants(vk->cmd, vk->pipelines.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
0, sizeof(struct vk_draw_uniform), &ubo);
|
||||
}
|
||||
|
||||
/* VBO is already uploaded. */
|
||||
vkCmdBindVertexBuffers(vk->cmd, 0, 1,
|
||||
&call->vbo->buffer, &call->vbo->offset);
|
||||
|
||||
/* Draw the quad */
|
||||
vkCmdDraw(vk->cmd, call->vertices, 1, 0, 0);
|
||||
}
|
||||
|
||||
void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
|
||||
{
|
||||
vulkan_transition_texture(vk, quad->texture);
|
||||
|
||||
if (quad->pipeline != vk->tracker.pipeline)
|
||||
{
|
||||
vkCmdBindPipeline(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, quad->pipeline);
|
||||
vk->tracker.pipeline = quad->pipeline;
|
||||
|
||||
/* Changing pipeline invalidates dynamic state. */
|
||||
vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT;
|
||||
}
|
||||
|
||||
vulkan_check_dynamic_state(vk);
|
||||
|
||||
/* Upload descriptors */
|
||||
{
|
||||
struct vk_draw_uniform ubo;
|
||||
VkDescriptorSet set;
|
||||
struct vk_buffer_range range;
|
||||
if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->ubo,
|
||||
sizeof(struct vk_draw_uniform), &range))
|
||||
return;
|
||||
|
||||
ubo.mvp = *quad->mvp;
|
||||
ubo.texsize[0] = quad->texture->width;
|
||||
ubo.texsize[1] = quad->texture->height;
|
||||
ubo.texsize[2] = 1.0f / quad->texture->width;
|
||||
ubo.texsize[3] = 1.0f / quad->texture->height;
|
||||
|
||||
if (quad->texture->view != vk->tracker.view || quad->sampler != vk->tracker.sampler)
|
||||
{
|
||||
set = vulkan_descriptor_manager_alloc(vk->context->device, &vk->chain->descriptor_manager);
|
||||
vulkan_write_quad_descriptors(vk->context->device,
|
||||
set,
|
||||
quad->texture,
|
||||
quad->sampler);
|
||||
|
||||
vkCmdBindDescriptorSets(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
vk->pipelines.layout, 0,
|
||||
1, &set, 0, NULL);
|
||||
|
||||
vk->tracker.view = quad->texture->view;
|
||||
vk->tracker.sampler = quad->sampler;
|
||||
}
|
||||
|
||||
vkCmdPushConstants(vk->cmd, vk->pipelines.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
0, sizeof(struct vk_draw_uniform), &ubo);
|
||||
}
|
||||
|
||||
/* Upload VBO */
|
||||
{
|
||||
struct vk_buffer_range range;
|
||||
if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->vbo,
|
||||
6 * sizeof(struct vk_vertex), &range))
|
||||
return;
|
||||
|
||||
vulkan_write_quad_vbo((struct vk_vertex*)range.data,
|
||||
0.0f, 0.0f, 1.0f, 1.0f,
|
||||
0.0f, 0.0f, 1.0f, 1.0f,
|
||||
&quad->color);
|
||||
|
||||
vkCmdBindVertexBuffers(vk->cmd, 0, 1,
|
||||
&range.buffer, &range.offset);
|
||||
}
|
||||
|
||||
/* Draw the quad */
|
||||
vkCmdDraw(vk->cmd, 6, 1, 0, 0);
|
||||
}
|
||||
|
||||
void vulkan_image_layout_transition(vk_t *vk, VkCommandBuffer cmd, VkImage image,
|
||||
VkImageLayout old_layout, VkImageLayout new_layout,
|
||||
VkAccessFlags srcAccess, VkAccessFlags dstAccess,
|
||||
VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages)
|
||||
{
|
||||
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
|
||||
barrier.srcAccessMask = srcAccess;
|
||||
barrier.dstAccessMask = dstAccess;
|
||||
barrier.oldLayout = old_layout;
|
||||
barrier.newLayout = new_layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
vkCmdPipelineBarrier(cmd,
|
||||
srcStages,
|
||||
dstStages,
|
||||
0,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
1, &barrier);
|
||||
}
|
||||
|
||||
struct vk_buffer vulkan_create_buffer(const struct vulkan_context *context,
|
||||
size_t size, VkBufferUsageFlags usage)
|
||||
{
|
||||
struct vk_buffer buffer;
|
||||
VkMemoryRequirements mem_reqs;
|
||||
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
|
||||
info.size = size;
|
||||
info.usage = usage;
|
||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vkCreateBuffer(context->device, &info, NULL, &buffer.buffer);
|
||||
|
||||
vkGetBufferMemoryRequirements(context->device, buffer.buffer, &mem_reqs);
|
||||
|
||||
alloc.allocationSize = mem_reqs.size;
|
||||
alloc.memoryTypeIndex = vulkan_find_memory_type(&context->memory_properties,
|
||||
mem_reqs.memoryTypeBits,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
vkAllocateMemory(context->device, &alloc, NULL, &buffer.memory);
|
||||
vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0);
|
||||
|
||||
buffer.size = alloc.allocationSize;
|
||||
|
||||
vkMapMemory(context->device, buffer.memory, 0, buffer.size, 0, &buffer.mapped);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void vulkan_destroy_buffer(VkDevice device, struct vk_buffer *buffer)
|
||||
{
|
||||
vkUnmapMemory(device, buffer->memory);
|
||||
vkFreeMemory(device, buffer->memory, NULL);
|
||||
vkDestroyBuffer(device, buffer->buffer, NULL);
|
||||
memset(buffer, 0, sizeof(*buffer));
|
||||
}
|
||||
|
||||
static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(VkDevice device,
|
||||
const struct vk_descriptor_manager *manager)
|
||||
{
|
||||
unsigned i;
|
||||
VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
|
||||
VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
|
||||
|
||||
struct vk_descriptor_pool *pool = (struct vk_descriptor_pool*)calloc(1, sizeof(*pool));
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
pool_info.maxSets = VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS;
|
||||
pool_info.poolSizeCount = manager->num_sizes;
|
||||
pool_info.pPoolSizes = manager->sizes;
|
||||
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
vkCreateDescriptorPool(device, &pool_info, NULL, &pool->pool);
|
||||
|
||||
/* Just allocate all descriptor sets up front. */
|
||||
alloc_info.descriptorPool = pool->pool;
|
||||
alloc_info.descriptorSetCount = 1;
|
||||
alloc_info.pSetLayouts = &manager->set_layout;
|
||||
for (i = 0; i < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS; i++)
|
||||
vkAllocateDescriptorSets(device, &alloc_info, &pool->sets[i]);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
VkDescriptorSet vulkan_descriptor_manager_alloc(VkDevice device, struct vk_descriptor_manager *manager)
|
||||
{
|
||||
if (manager->count < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS)
|
||||
return manager->current->sets[manager->count++];
|
||||
|
||||
while (manager->current->next)
|
||||
{
|
||||
manager->current = manager->current->next;
|
||||
manager->count = 0;
|
||||
return manager->current->sets[manager->count++];
|
||||
}
|
||||
|
||||
manager->current->next = vulkan_alloc_descriptor_pool(device, manager);
|
||||
retro_assert(manager->current->next);
|
||||
|
||||
manager->current = manager->current->next;
|
||||
manager->count = 0;
|
||||
return manager->current->sets[manager->count++];
|
||||
}
|
||||
|
||||
void vulkan_descriptor_manager_restart(struct vk_descriptor_manager *manager)
|
||||
{
|
||||
manager->current = manager->head;
|
||||
manager->count = 0;
|
||||
}
|
||||
|
||||
struct vk_descriptor_manager vulkan_create_descriptor_manager(VkDevice device,
|
||||
const VkDescriptorPoolSize *sizes, unsigned num_sizes, VkDescriptorSetLayout set_layout)
|
||||
{
|
||||
struct vk_descriptor_manager manager;
|
||||
memset(&manager, 0, sizeof(manager));
|
||||
retro_assert(num_sizes <= VULKAN_MAX_DESCRIPTOR_POOL_SIZES);
|
||||
memcpy(manager.sizes, sizes, num_sizes * sizeof(*sizes));
|
||||
manager.num_sizes = num_sizes;
|
||||
manager.set_layout = set_layout;
|
||||
|
||||
manager.head = vulkan_alloc_descriptor_pool(device, &manager);
|
||||
retro_assert(manager.head);
|
||||
return manager;
|
||||
}
|
||||
|
||||
void vulkan_destroy_descriptor_manager(VkDevice device, struct vk_descriptor_manager *manager)
|
||||
{
|
||||
struct vk_descriptor_pool *node = manager->head;
|
||||
|
||||
while (node)
|
||||
{
|
||||
struct vk_descriptor_pool *next = node->next;
|
||||
|
||||
vkFreeDescriptorSets(device, node->pool, VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS, node->sets);
|
||||
vkDestroyDescriptorPool(device, node->pool, NULL);
|
||||
|
||||
free(node);
|
||||
node = next;
|
||||
}
|
||||
|
||||
memset(manager, 0, sizeof(*manager));
|
||||
}
|
||||
|
||||
static void vulkan_buffer_chain_step(struct vk_buffer_chain *chain)
|
||||
{
|
||||
chain->current = chain->current->next;
|
||||
chain->offset = 0;
|
||||
}
|
||||
|
||||
static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range)
|
||||
{
|
||||
VkDeviceSize next_offset = chain->offset + size;
|
||||
if (next_offset <= chain->current->buffer.size)
|
||||
{
|
||||
range->data = (uint8_t*)chain->current->buffer.mapped + chain->offset;
|
||||
range->buffer = chain->current->buffer.buffer;
|
||||
range->offset = chain->offset;
|
||||
chain->offset = (next_offset + chain->alignment - 1) & ~(chain->alignment - 1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct vk_buffer_node *vulkan_buffer_chain_alloc_node(
|
||||
const struct vulkan_context *context,
|
||||
size_t size, VkBufferUsageFlags usage)
|
||||
{
|
||||
struct vk_buffer_node *node = (struct vk_buffer_node*)calloc(1, sizeof(*node));
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
node->buffer = vulkan_create_buffer(context, size, usage);
|
||||
return node;
|
||||
}
|
||||
|
||||
struct vk_buffer_chain vulkan_buffer_chain_init(VkDeviceSize block_size,
|
||||
VkDeviceSize alignment,
|
||||
VkBufferUsageFlags usage)
|
||||
{
|
||||
struct vk_buffer_chain chain = { block_size, alignment, 0, usage, NULL, NULL };
|
||||
return chain;
|
||||
}
|
||||
|
||||
void vulkan_buffer_chain_discard(struct vk_buffer_chain *chain)
|
||||
{
|
||||
chain->current = chain->head;
|
||||
chain->offset = 0;
|
||||
}
|
||||
|
||||
bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
|
||||
struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range)
|
||||
{
|
||||
if (!chain->head)
|
||||
{
|
||||
chain->head = vulkan_buffer_chain_alloc_node(context,
|
||||
chain->block_size, chain->usage);
|
||||
if (!chain->head)
|
||||
return false;
|
||||
|
||||
chain->current = chain->head;
|
||||
chain->offset = 0;
|
||||
}
|
||||
|
||||
if (vulkan_buffer_chain_suballoc(chain, size, range))
|
||||
return true;
|
||||
|
||||
/* We've exhausted the current chain, traverse list until we
|
||||
* can find a block we can use. Usually, we just step once. */
|
||||
while (chain->current->next)
|
||||
{
|
||||
vulkan_buffer_chain_step(chain);
|
||||
if (vulkan_buffer_chain_suballoc(chain, size, range))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We have to allocate a new node, might allocate larger
|
||||
* buffer here than block_size in case we have a very large allocation. */
|
||||
if (size < chain->block_size)
|
||||
size = chain->block_size;
|
||||
|
||||
chain->current->next = vulkan_buffer_chain_alloc_node(
|
||||
context, size, chain->usage);
|
||||
if (!chain->current->next)
|
||||
return false;
|
||||
|
||||
vulkan_buffer_chain_step(chain);
|
||||
/* This cannot possibly fail. */
|
||||
retro_assert(vulkan_buffer_chain_suballoc(chain, size, range));
|
||||
return true;
|
||||
}
|
||||
|
||||
void vulkan_buffer_chain_free(VkDevice device, struct vk_buffer_chain *chain)
|
||||
{
|
||||
struct vk_buffer_node *node = chain->head;
|
||||
while (node)
|
||||
{
|
||||
struct vk_buffer_node *next = node->next;
|
||||
vulkan_destroy_buffer(device, &node->buffer);
|
||||
|
||||
free(node);
|
||||
node = next;
|
||||
}
|
||||
memset(chain, 0, sizeof(*chain));
|
||||
}
|
||||
|
412
gfx/common/vulkan_common.h
Normal file
412
gfx/common/vulkan_common.h
Normal file
@ -0,0 +1,412 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VULKAN_COMMON_H__
|
||||
#define VULKAN_COMMON_H__
|
||||
|
||||
#define VK_PROTOTYPES
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <gfx/math/matrix_4x4.h>
|
||||
#include <formats/image.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include "boolean.h"
|
||||
#include "../../driver.h"
|
||||
#include "../../performance.h"
|
||||
#include "../../libretro.h"
|
||||
#include "../../general.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../font_driver.h"
|
||||
#include "../video_context_driver.h"
|
||||
#include "libretro_vulkan.h"
|
||||
#include "../drivers_shader/shader_vulkan.h"
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <gfx/scaler/scaler.h>
|
||||
|
||||
#define VULKAN_MAX_SWAPCHAIN_IMAGES 8
|
||||
|
||||
#define VULKAN_DIRTY_DYNAMIC_BIT 0x0001
|
||||
|
||||
typedef struct vulkan_context
|
||||
{
|
||||
VkInstance instance;
|
||||
VkPhysicalDevice gpu;
|
||||
VkDevice device;
|
||||
VkQueue queue;
|
||||
uint32_t graphics_queue_index;
|
||||
|
||||
VkPhysicalDeviceProperties gpu_properties;
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
|
||||
bool invalid_swapchain;
|
||||
VkImage swapchain_images[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
VkFence swapchain_fences[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
VkSemaphore swapchain_semaphores[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
uint32_t num_swapchain_images;
|
||||
uint32_t current_swapchain_index;
|
||||
unsigned swapchain_width;
|
||||
unsigned swapchain_height;
|
||||
VkFormat swapchain_format;
|
||||
|
||||
slock_t *queue_lock;
|
||||
|
||||
/* Used by screenshot to get blits with correct colorspace. */
|
||||
bool swapchain_is_srgb;
|
||||
} vulkan_context_t;
|
||||
|
||||
struct vk_draw_uniform
|
||||
{
|
||||
math_matrix_4x4 mvp;
|
||||
float texsize[4];
|
||||
};
|
||||
|
||||
struct vk_color
|
||||
{
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
struct vk_vertex
|
||||
{
|
||||
float x, y;
|
||||
float tex_x, tex_y;
|
||||
struct vk_color color;
|
||||
};
|
||||
|
||||
struct vk_image
|
||||
{
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkFramebuffer framebuffer;
|
||||
};
|
||||
|
||||
struct vk_texture
|
||||
{
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
|
||||
unsigned width, height;
|
||||
VkFormat format;
|
||||
|
||||
void *mapped;
|
||||
size_t offset;
|
||||
size_t stride;
|
||||
size_t size;
|
||||
VkDeviceSize memory_size;
|
||||
uint32_t memory_type;
|
||||
|
||||
VkImageLayout layout;
|
||||
bool default_smooth;
|
||||
};
|
||||
|
||||
struct vk_buffer
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory memory;
|
||||
VkDeviceSize size;
|
||||
void *mapped;
|
||||
};
|
||||
|
||||
struct vk_buffer_node
|
||||
{
|
||||
struct vk_buffer buffer;
|
||||
struct vk_buffer_node *next;
|
||||
};
|
||||
|
||||
struct vk_buffer_chain
|
||||
{
|
||||
VkDeviceSize block_size;
|
||||
VkDeviceSize alignment;
|
||||
VkDeviceSize offset;
|
||||
VkBufferUsageFlags usage;
|
||||
struct vk_buffer_node *head;
|
||||
struct vk_buffer_node *current;
|
||||
};
|
||||
|
||||
struct vk_buffer_range
|
||||
{
|
||||
uint8_t *data;
|
||||
VkBuffer buffer;
|
||||
VkDeviceSize offset;
|
||||
};
|
||||
|
||||
struct vk_buffer_chain vulkan_buffer_chain_init(
|
||||
VkDeviceSize block_size,
|
||||
VkDeviceSize alignment,
|
||||
VkBufferUsageFlags usage);
|
||||
void vulkan_buffer_chain_discard(struct vk_buffer_chain *chain);
|
||||
bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
|
||||
struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range);
|
||||
void vulkan_buffer_chain_free(VkDevice device, struct vk_buffer_chain *chain);
|
||||
|
||||
#define VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS 16
|
||||
#define VULKAN_BUFFER_BLOCK_SIZE (4 * 1024)
|
||||
#define VULKAN_MAX_DESCRIPTOR_POOL_SIZES 16
|
||||
|
||||
struct vk_descriptor_pool
|
||||
{
|
||||
VkDescriptorPool pool;
|
||||
VkDescriptorSet sets[VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS];
|
||||
struct vk_descriptor_pool *next;
|
||||
};
|
||||
|
||||
struct vk_descriptor_manager
|
||||
{
|
||||
struct vk_descriptor_pool *head;
|
||||
struct vk_descriptor_pool *current;
|
||||
unsigned count;
|
||||
|
||||
VkDescriptorPoolSize sizes[VULKAN_MAX_DESCRIPTOR_POOL_SIZES];
|
||||
VkDescriptorSetLayout set_layout;
|
||||
unsigned num_sizes;
|
||||
};
|
||||
|
||||
struct vk_per_frame
|
||||
{
|
||||
struct vk_image backbuffer;
|
||||
struct vk_texture texture;
|
||||
struct vk_buffer_chain vbo;
|
||||
struct vk_buffer_chain ubo;
|
||||
struct vk_descriptor_manager descriptor_manager;
|
||||
|
||||
VkCommandPool cmd_pool;
|
||||
VkCommandBuffer cmd;
|
||||
};
|
||||
|
||||
struct vk_draw_quad
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
struct vk_texture *texture;
|
||||
VkSampler sampler;
|
||||
const math_matrix_4x4 *mvp;
|
||||
struct vk_color color;
|
||||
};
|
||||
|
||||
struct vk_draw_triangles
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
struct vk_texture *texture;
|
||||
VkSampler sampler;
|
||||
const math_matrix_4x4 *mvp;
|
||||
|
||||
const struct vk_buffer_range *vbo;
|
||||
unsigned vertices;
|
||||
};
|
||||
|
||||
typedef struct vk
|
||||
{
|
||||
vulkan_context_t *context;
|
||||
video_info_t video;
|
||||
unsigned full_x, full_y;
|
||||
|
||||
unsigned tex_w, tex_h;
|
||||
VkFormat tex_fmt;
|
||||
bool vsync;
|
||||
bool keep_aspect;
|
||||
bool fullscreen;
|
||||
bool quitting;
|
||||
bool should_resize;
|
||||
unsigned vp_out_width, vp_out_height;
|
||||
|
||||
unsigned rotation;
|
||||
math_matrix_4x4 mvp, mvp_no_rot;
|
||||
struct video_viewport vp;
|
||||
VkViewport vk_vp;
|
||||
|
||||
VkRenderPass render_pass;
|
||||
struct vk_per_frame swapchain[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
unsigned num_swapchain_images;
|
||||
|
||||
VkCommandBuffer cmd; /* Currently active command buffer. */
|
||||
VkCommandPool staging_pool; /* Staging pool for doing buffer transfers on GPU. */
|
||||
|
||||
struct
|
||||
{
|
||||
struct vk_texture staging[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
struct scaler_ctx scaler;
|
||||
bool pending;
|
||||
bool streamed;
|
||||
} readback;
|
||||
|
||||
struct
|
||||
{
|
||||
struct vk_texture *images;
|
||||
struct vk_vertex *vertex;
|
||||
unsigned count;
|
||||
bool enable;
|
||||
bool full_screen;
|
||||
} overlay;
|
||||
|
||||
struct
|
||||
{
|
||||
VkPipeline alpha_blend;
|
||||
VkDescriptorSetLayout set_layout;
|
||||
VkPipelineLayout layout;
|
||||
VkPipelineCache cache;
|
||||
} pipelines;
|
||||
|
||||
struct
|
||||
{
|
||||
bool blend;
|
||||
VkPipeline pipelines[4];
|
||||
struct vk_texture blank_texture;
|
||||
} display;
|
||||
|
||||
struct
|
||||
{
|
||||
struct vk_texture textures[VULKAN_MAX_SWAPCHAIN_IMAGES];
|
||||
float alpha;
|
||||
unsigned last_index;
|
||||
bool enable;
|
||||
bool full_screen;
|
||||
} menu;
|
||||
|
||||
struct
|
||||
{
|
||||
VkSampler linear;
|
||||
VkSampler nearest;
|
||||
} samplers;
|
||||
|
||||
unsigned last_valid_index;
|
||||
|
||||
struct vk_per_frame *chain;
|
||||
|
||||
struct
|
||||
{
|
||||
struct retro_hw_render_interface_vulkan iface;
|
||||
const struct retro_vulkan_image *image;
|
||||
const VkSemaphore *semaphores;
|
||||
uint32_t num_semaphores;
|
||||
|
||||
VkPipelineStageFlags *wait_dst_stages;
|
||||
|
||||
VkCommandBuffer *cmd;
|
||||
uint32_t num_cmd;
|
||||
unsigned capacity_cmd;
|
||||
|
||||
unsigned last_width;
|
||||
unsigned last_height;
|
||||
|
||||
bool enable;
|
||||
} hw;
|
||||
|
||||
struct
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
VkImageView view;
|
||||
VkSampler sampler;
|
||||
uint64_t dirty;
|
||||
} tracker;
|
||||
|
||||
vulkan_filter_chain_t *filter_chain;
|
||||
} vk_t;
|
||||
|
||||
uint32_t vulkan_find_memory_type(const VkPhysicalDeviceMemoryProperties *mem_props,
|
||||
uint32_t device_reqs, uint32_t host_reqs);
|
||||
|
||||
uint32_t vulkan_find_memory_type_fallback(const VkPhysicalDeviceMemoryProperties *mem_props,
|
||||
uint32_t device_reqs, uint32_t host_reqs);
|
||||
|
||||
enum vk_texture_type
|
||||
{
|
||||
VULKAN_TEXTURE_STREAMED = 0,
|
||||
VULKAN_TEXTURE_STATIC,
|
||||
VULKAN_TEXTURE_READBACK
|
||||
};
|
||||
|
||||
struct vk_texture vulkan_create_texture(vk_t *vk,
|
||||
struct vk_texture *old,
|
||||
unsigned width, unsigned height,
|
||||
VkFormat format,
|
||||
const void *initial, const VkComponentMapping *swizzle,
|
||||
enum vk_texture_type type);
|
||||
|
||||
void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture);
|
||||
|
||||
void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *tex);
|
||||
void vulkan_destroy_texture(VkDevice device, struct vk_texture *tex);
|
||||
|
||||
/* VBO will be written to here. */
|
||||
void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad);
|
||||
|
||||
/* The VBO needs to be written to before calling this.
|
||||
* Use vulkan_buffer_chain_alloc.
|
||||
*/
|
||||
void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call);
|
||||
|
||||
void vulkan_image_layout_transition(vk_t *vk, VkCommandBuffer cmd, VkImage image,
|
||||
VkImageLayout old_layout, VkImageLayout new_layout,
|
||||
VkAccessFlags srcAccess, VkAccessFlags dstAccess,
|
||||
VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages);
|
||||
|
||||
static inline unsigned vulkan_format_to_bpp(VkFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return 4;
|
||||
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
return 2;
|
||||
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
RARCH_ERR("[Vulkan]: Unknown format.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vulkan_write_quad_vbo(struct vk_vertex *pv,
|
||||
float x, float y, float width, float height,
|
||||
float tex_x, float tex_y, float tex_width, float tex_height,
|
||||
const struct vk_color *color)
|
||||
{
|
||||
unsigned i;
|
||||
static const float strip[2 * 6] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
pv[i].x = x + strip[2 * i + 0] * width;
|
||||
pv[i].y = y + strip[2 * i + 1] * height;
|
||||
pv[i].tex_x = tex_x + strip[2 * i + 0] * tex_width;
|
||||
pv[i].tex_y = tex_y + strip[2 * i + 1] * tex_height;
|
||||
pv[i].color = *color;
|
||||
}
|
||||
}
|
||||
|
||||
struct vk_buffer vulkan_create_buffer(const struct vulkan_context *context,
|
||||
size_t size, VkBufferUsageFlags usage);
|
||||
void vulkan_destroy_buffer(VkDevice device, struct vk_buffer *buffer);
|
||||
|
||||
VkDescriptorSet vulkan_descriptor_manager_alloc(VkDevice device, struct vk_descriptor_manager *manager);
|
||||
void vulkan_descriptor_manager_restart(struct vk_descriptor_manager *manager);
|
||||
struct vk_descriptor_manager vulkan_create_descriptor_manager(VkDevice device,
|
||||
const VkDescriptorPoolSize *sizes, unsigned num_sizes,
|
||||
VkDescriptorSetLayout set_layout);
|
||||
void vulkan_destroy_descriptor_manager(VkDevice device,
|
||||
struct vk_descriptor_manager *manager);
|
||||
#endif
|
||||
|
@ -3850,13 +3850,14 @@ static uintptr_t gl_load_texture(void *video_data, void *data,
|
||||
return id;
|
||||
}
|
||||
|
||||
static void gl_unload_texture(void *data, uintptr_t *id)
|
||||
static void gl_unload_texture(void *data, uintptr_t id)
|
||||
{
|
||||
GLuint glid;
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
glDeleteTextures(1, (const GLuint*)id);
|
||||
*id = 0;
|
||||
glid = (GLuint)id;
|
||||
glDeleteTextures(1, &glid);
|
||||
}
|
||||
|
||||
static const video_poke_interface_t gl_poke_interface = {
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <retro_assert.h>
|
||||
#include <gfx/scaler/scaler.h>
|
||||
#include <retro_assert.h>
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
|
2011
gfx/drivers/vulkan.c
Normal file
2011
gfx/drivers/vulkan.c
Normal file
File diff suppressed because it is too large
Load Diff
23
gfx/drivers/vulkan_shaders/Makefile
Normal file
23
gfx/drivers/vulkan_shaders/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
VERT_SHADERS := $(wildcard *.vert)
|
||||
FRAG_SHADERS := $(wildcard *.frag)
|
||||
SPIRV := $(VERT_SHADERS:.vert=.vert.spv) $(FRAG_SHADERS:.frag=.frag.spv)
|
||||
INCLUDES := $(SPIRV:.spv=.inc)
|
||||
|
||||
GLSLANG := glslangValidator
|
||||
|
||||
all: $(INCLUDES)
|
||||
|
||||
%.frag.spv: %.frag
|
||||
$(GLSLANG) -V -o $@ $<
|
||||
|
||||
%.vert.spv: %.vert
|
||||
$(GLSLANG) -V -o $@ $<
|
||||
|
||||
%.inc: %.spv
|
||||
xxd -i $< $@
|
||||
|
||||
clean:
|
||||
rm -f $(INCLUDES)
|
||||
rm -f $(SPIRV)
|
||||
|
||||
.PHONY: clean
|
11
gfx/drivers/vulkan_shaders/alpha_blend.frag
Normal file
11
gfx/drivers/vulkan_shaders/alpha_blend.frag
Normal file
@ -0,0 +1,11 @@
|
||||
#version 310 es
|
||||
precision highp float;
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 1) in vec4 vColor;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(set = 0, binding = 0) uniform highp sampler2D uTex;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vColor * texture(uTex, vTexCoord);
|
||||
}
|
59
gfx/drivers/vulkan_shaders/alpha_blend.frag.inc
Normal file
59
gfx/drivers/vulkan_shaders/alpha_blend.frag.inc
Normal file
@ -0,0 +1,59 @@
|
||||
unsigned char alpha_blend_frag_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x76, 0x43, 0x6f, 0x6c,
|
||||
0x6f, 0x72, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x75, 0x54, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x76, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72,
|
||||
0x64, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
||||
0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int alpha_blend_frag_spv_len = 664;
|
19
gfx/drivers/vulkan_shaders/alpha_blend.vert
Normal file
19
gfx/drivers/vulkan_shaders/alpha_blend.vert
Normal file
@ -0,0 +1,19 @@
|
||||
#version 310 es
|
||||
layout(location = 0) in vec4 Position;
|
||||
layout(location = 1) in vec2 TexCoord;
|
||||
layout(location = 2) in vec4 Color;
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
layout(location = 1) out vec4 vColor;
|
||||
|
||||
layout(push_constant, std140) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
vec4 texsize;
|
||||
} global;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = global.MVP * Position;
|
||||
vTexCoord = TexCoord;
|
||||
vColor = Color;
|
||||
}
|
113
gfx/drivers/vulkan_shaders/alpha_blend.vert.inc
Normal file
113
gfx/drivers/vulkan_shaders/alpha_blend.vert.inc
Normal file
@ -0,0 +1,113 @@
|
||||
unsigned char alpha_blend_vert_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50,
|
||||
0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00,
|
||||
0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x55, 0x42, 0x4f, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4d, 0x56, 0x50, 0x00, 0x06, 0x00, 0x05, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x76, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x54, 0x65, 0x78, 0x43,
|
||||
0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x76, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6c, 0x6f,
|
||||
0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
||||
0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int alpha_blend_vert_spv_len = 1312;
|
19
gfx/drivers/vulkan_shaders/font.vert
Normal file
19
gfx/drivers/vulkan_shaders/font.vert
Normal file
@ -0,0 +1,19 @@
|
||||
#version 310 es
|
||||
layout(location = 0) in vec4 Position;
|
||||
layout(location = 1) in vec2 TexCoord;
|
||||
layout(location = 2) in vec4 Color;
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
layout(location = 1) out vec4 vColor;
|
||||
|
||||
layout(push_constant, std140) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
vec4 texsize;
|
||||
} global;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = global.MVP * Position;
|
||||
vTexCoord = TexCoord;
|
||||
vColor = Color;
|
||||
}
|
113
gfx/drivers/vulkan_shaders/font.vert.inc
Normal file
113
gfx/drivers/vulkan_shaders/font.vert.inc
Normal file
@ -0,0 +1,113 @@
|
||||
unsigned char font_vert_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50,
|
||||
0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00,
|
||||
0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x55, 0x42, 0x4f, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4d, 0x56, 0x50, 0x00, 0x06, 0x00, 0x05, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x73,
|
||||
0x69, 0x7a, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x76, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x54, 0x65, 0x78, 0x43,
|
||||
0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x76, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6c, 0x6f,
|
||||
0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x23, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x23, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
||||
0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int font_vert_spv_len = 1312;
|
10
gfx/drivers/vulkan_shaders/opaque.frag
Normal file
10
gfx/drivers/vulkan_shaders/opaque.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 310 es
|
||||
precision highp float;
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(set = 0, binding = 2) uniform highp sampler2D Source;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(texture(Source, vTexCoord).rgb, 1.0);
|
||||
}
|
63
gfx/drivers/vulkan_shaders/opaque.frag.inc
Normal file
63
gfx/drivers/vulkan_shaders/opaque.frag.inc
Normal file
@ -0,0 +1,63 @@
|
||||
unsigned char opaque_frag_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x72, 0x61, 0x67,
|
||||
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x54, 0x65, 0x78,
|
||||
0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x11, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
||||
0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int opaque_frag_spv_len = 712;
|
15
gfx/drivers/vulkan_shaders/opaque.vert
Normal file
15
gfx/drivers/vulkan_shaders/opaque.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 310 es
|
||||
layout(location = 0) in vec4 Position;
|
||||
layout(location = 1) in vec2 TexCoord;
|
||||
layout(location = 0) out vec2 vTexCoord;
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
} global;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = global.MVP * Position;
|
||||
vTexCoord = TexCoord;
|
||||
}
|
99
gfx/drivers/vulkan_shaders/opaque.vert.inc
Normal file
99
gfx/drivers/vulkan_shaders/opaque.vert.inc
Normal file
@ -0,0 +1,99 @@
|
||||
unsigned char opaque_vert_spv[] = {
|
||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00,
|
||||
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x53, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x55, 0x42, 0x4f, 0x00, 0x06, 0x00, 0x04, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x56, 0x50, 0x00,
|
||||
0x05, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x6f, 0x62,
|
||||
0x61, 0x6c, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x76, 0x54, 0x65, 0x78,
|
||||
0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||
0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x49, 0x44, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x22, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x47, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
||||
0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
||||
0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
||||
0x16, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x03, 0x00, 0x19, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
||||
0x3d, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
|
||||
};
|
||||
unsigned int opaque_vert_spv_len = 1152;
|
@ -452,7 +452,7 @@ static bool gfx_ctx_wl_set_video_mode(void *data,
|
||||
wl->win = wl_egl_window_create(wl->surface, wl->width, wl->height);
|
||||
wl->shell_surf = wl_shell_get_shell_surface(wl->shell, wl->surface);
|
||||
|
||||
wl_shell_surface_add_listener(wl->shell_surf, &shell_surface_listener, NULL);
|
||||
wl_shell_surface_add_listener(wl->shell_surf, &shell_surface_listener, wl);
|
||||
wl_shell_surface_set_toplevel(wl->shell_surf);
|
||||
wl_shell_surface_set_class(wl->shell_surf, "RetroArch");
|
||||
wl_shell_surface_set_title(wl->shell_surf, "RetroArch");
|
||||
|
824
gfx/drivers_context/wayland_ctx_vulkan.c
Normal file
824
gfx/drivers_context/wayland_ctx_vulkan.c
Normal file
@ -0,0 +1,824 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2016 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2015 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#include "../common/vulkan_common.h"
|
||||
#include "../video_context_driver.h"
|
||||
|
||||
#include <sys/poll.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "../../driver.h"
|
||||
#include "../../general.h"
|
||||
#include "../../runloop.h"
|
||||
|
||||
static volatile sig_atomic_t g_quit = 0;
|
||||
|
||||
static VkInstance cached_instance;
|
||||
static VkDevice cached_device;
|
||||
|
||||
static void sighandler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
g_quit = 1;
|
||||
}
|
||||
|
||||
static void install_sighandlers(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_sigaction = NULL;
|
||||
sa.sa_handler = sighandler;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGTERM, &sa, NULL);
|
||||
}
|
||||
|
||||
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) do { \
|
||||
wl->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
|
||||
if (wl->fp##entrypoint == NULL) { \
|
||||
RARCH_ERR("vkGetInstanceProcAddr failed to find vk%s\n", #entrypoint); \
|
||||
goto error; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) do { \
|
||||
wl->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk" #entrypoint); \
|
||||
if (wl->fp##entrypoint == NULL) { \
|
||||
RARCH_ERR("vkGetDeviceProcAddr failed to find vk%s\n", #entrypoint); \
|
||||
goto error; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
typedef struct gfx_ctx_wayland_data
|
||||
{
|
||||
struct vulkan_context context;
|
||||
|
||||
bool resize;
|
||||
int fd;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
struct wl_display *dpy;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_surface *surf;
|
||||
struct wl_shell_surface *shell_surf;
|
||||
struct wl_shell *shell;
|
||||
unsigned swap_interval;
|
||||
bool need_new_swapchain;
|
||||
|
||||
unsigned buffer_scale;
|
||||
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
|
||||
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
|
||||
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
|
||||
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
|
||||
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
|
||||
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
|
||||
PFN_vkQueuePresentKHR fpQueuePresentKHR;
|
||||
PFN_vkCreateWaylandSurfaceKHR fpCreateWaylandSurfaceKHR;
|
||||
PFN_vkDestroySurfaceKHR fpDestroySurfaceKHR;
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
VkSwapchainKHR swapchain;
|
||||
} gfx_ctx_wayland_data_t;
|
||||
|
||||
static bool vulkan_create_swapchain(gfx_ctx_wayland_data_t *wl);
|
||||
|
||||
/* Shell surface callbacks. */
|
||||
static void shell_surface_handle_ping(void *data,
|
||||
struct wl_shell_surface *shell_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
(void)data;
|
||||
wl_shell_surface_pong(shell_surface, serial);
|
||||
}
|
||||
|
||||
static void shell_surface_handle_configure(void *data,
|
||||
struct wl_shell_surface *shell_surface,
|
||||
uint32_t edges, int32_t width, int32_t height)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
(void)shell_surface;
|
||||
(void)edges;
|
||||
|
||||
wl->width = wl->buffer_scale * width;
|
||||
wl->height = wl->buffer_scale * height;
|
||||
|
||||
RARCH_LOG("[Wayland/Vulkan]: Surface configure: %u x %u.\n",
|
||||
wl->width, wl->height);
|
||||
}
|
||||
|
||||
static void shell_surface_handle_popup_done(void *data,
|
||||
struct wl_shell_surface *shell_surface)
|
||||
{
|
||||
(void)data;
|
||||
(void)shell_surface;
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
shell_surface_handle_ping,
|
||||
shell_surface_handle_configure,
|
||||
shell_surface_handle_popup_done,
|
||||
};
|
||||
|
||||
/* Registry callbacks. */
|
||||
static void registry_handle_global(void *data, struct wl_registry *reg,
|
||||
uint32_t id, const char *interface, uint32_t version)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
(void)version;
|
||||
|
||||
if (!strcmp(interface, "wl_compositor"))
|
||||
wl->compositor = (struct wl_compositor*)wl_registry_bind(reg, id, &wl_compositor_interface, 3);
|
||||
else if (!strcmp(interface, "wl_shell"))
|
||||
wl->shell = (struct wl_shell*)wl_registry_bind(reg, id, &wl_shell_interface, 1);
|
||||
}
|
||||
|
||||
static void registry_handle_global_remove(void *data,
|
||||
struct wl_registry *registry, uint32_t id)
|
||||
{
|
||||
(void)data;
|
||||
(void)registry;
|
||||
(void)id;
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handle_global,
|
||||
registry_handle_global_remove,
|
||||
};
|
||||
|
||||
static void gfx_ctx_wl_get_video_size(void *data,
|
||||
unsigned *width, unsigned *height);
|
||||
|
||||
static void gfx_ctx_wl_destroy_resources(gfx_ctx_wayland_data_t *wl)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!wl)
|
||||
return;
|
||||
|
||||
if (wl->context.queue)
|
||||
vkQueueWaitIdle(wl->context.queue);
|
||||
|
||||
if (wl->swapchain)
|
||||
wl->fpDestroySwapchainKHR(wl->context.device, wl->swapchain, NULL);
|
||||
|
||||
if (wl->surface)
|
||||
wl->fpDestroySurfaceKHR(wl->context.instance, wl->surface, NULL);
|
||||
|
||||
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
|
||||
{
|
||||
if (wl->context.swapchain_semaphores[i] != VK_NULL_HANDLE)
|
||||
vkDestroySemaphore(wl->context.device, wl->context.swapchain_semaphores[i], NULL);
|
||||
if (wl->context.swapchain_fences[i] != VK_NULL_HANDLE)
|
||||
vkDestroyFence(wl->context.device, wl->context.swapchain_fences[i], NULL);
|
||||
}
|
||||
|
||||
if (video_driver_ctl(RARCH_DISPLAY_CTL_IS_VIDEO_CACHE_CONTEXT, NULL))
|
||||
{
|
||||
cached_device = wl->context.device;
|
||||
cached_instance = wl->context.instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wl->context.device)
|
||||
vkDestroyDevice(wl->context.device, NULL);
|
||||
if (wl->context.instance)
|
||||
vkDestroyInstance(wl->context.instance, NULL);
|
||||
}
|
||||
|
||||
if (wl->fd >= 0)
|
||||
close(wl->fd);
|
||||
|
||||
if (wl->shell_surf)
|
||||
wl_shell_surface_destroy(wl->shell_surf);
|
||||
if (wl->surf)
|
||||
wl_surface_destroy(wl->surf);
|
||||
if (wl->compositor)
|
||||
wl_compositor_destroy(wl->compositor);
|
||||
if (wl->registry)
|
||||
wl_registry_destroy(wl->registry);
|
||||
if (wl->dpy)
|
||||
wl_display_disconnect(wl->dpy);
|
||||
|
||||
wl->dpy = NULL;
|
||||
wl->shell = NULL;
|
||||
wl->compositor = NULL;
|
||||
wl->registry = NULL;
|
||||
wl->dpy = NULL;
|
||||
wl->shell_surf = NULL;
|
||||
wl->surf = NULL;
|
||||
|
||||
wl->width = 0;
|
||||
wl->height = 0;
|
||||
}
|
||||
|
||||
static void flush_wayland_fd(gfx_ctx_wayland_data_t *wl)
|
||||
{
|
||||
struct pollfd fd = {0};
|
||||
|
||||
wl_display_dispatch_pending(wl->dpy);
|
||||
wl_display_flush(wl->dpy);
|
||||
|
||||
fd.fd = wl->fd;
|
||||
fd.events = POLLIN | POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
if (poll(&fd, 1, 0) > 0)
|
||||
{
|
||||
if (fd.revents & (POLLERR | POLLHUP))
|
||||
{
|
||||
close(wl->fd);
|
||||
g_quit = true;
|
||||
}
|
||||
|
||||
if (fd.revents & POLLIN)
|
||||
wl_display_dispatch(wl->dpy);
|
||||
if (fd.revents & POLLOUT)
|
||||
wl_display_flush(wl->dpy);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_check_window(void *data, bool *quit,
|
||||
bool *resize, unsigned *width, unsigned *height,
|
||||
unsigned frame_count)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
unsigned new_width, new_height;
|
||||
|
||||
(void)frame_count;
|
||||
|
||||
flush_wayland_fd(wl);
|
||||
|
||||
new_width = *width;
|
||||
new_height = *height;
|
||||
|
||||
gfx_ctx_wl_get_video_size(wl, &new_width, &new_height);
|
||||
|
||||
/* Swapchains are recreated in set_resize as a central place, so use that to trigger swapchain reinit. */
|
||||
*resize = wl->need_new_swapchain;
|
||||
|
||||
if (new_width != *width || new_height != *height)
|
||||
{
|
||||
*resize = true;
|
||||
*width = new_width;
|
||||
*height = new_height;
|
||||
}
|
||||
|
||||
*quit = g_quit;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
wl->width = width;
|
||||
wl->height = height;
|
||||
if (!vulkan_create_swapchain(wl))
|
||||
{
|
||||
RARCH_ERR("[Wayland/Vulkan]: Failed to update swapchain.\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
wl->context.invalid_swapchain = true;
|
||||
|
||||
wl->need_new_swapchain = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_update_window_title(void *data)
|
||||
{
|
||||
char buf[128] = {0};
|
||||
char buf_fps[128] = {0};
|
||||
settings_t *settings = config_get_ptr();
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
if (video_monitor_get_fps(buf, sizeof(buf),
|
||||
buf_fps, sizeof(buf_fps)))
|
||||
wl_shell_surface_set_title(wl->shell_surf, buf);
|
||||
|
||||
if (settings->fps_show)
|
||||
runloop_msg_queue_push(buf_fps, 1, 1, false);
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_get_video_size(void *data,
|
||||
unsigned *width, unsigned *height)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
*width = wl->width;
|
||||
*height = wl->height;
|
||||
}
|
||||
|
||||
#define DEFAULT_WINDOWED_WIDTH 640
|
||||
#define DEFAULT_WINDOWED_HEIGHT 480
|
||||
|
||||
static void *gfx_ctx_wl_init(void *video_driver)
|
||||
{
|
||||
VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
|
||||
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
|
||||
VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
|
||||
VkPhysicalDeviceFeatures features = { false };
|
||||
VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
|
||||
uint32_t gpu_count = 1;
|
||||
uint32_t queue_count;
|
||||
bool found_queue = false;
|
||||
unsigned i;
|
||||
VkQueueFamilyProperties queue_properties[32];
|
||||
static const float one = 1.0f;
|
||||
|
||||
static const char *instance_extensions[] = {
|
||||
"VK_KHR_surface",
|
||||
"VK_KHR_wayland_surface",
|
||||
};
|
||||
|
||||
static const char *device_extensions[] = {
|
||||
"VK_KHR_swapchain",
|
||||
};
|
||||
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)
|
||||
calloc(1, sizeof(gfx_ctx_wayland_data_t));
|
||||
|
||||
if (!wl)
|
||||
return NULL;
|
||||
|
||||
wl->dpy = wl_display_connect(NULL);
|
||||
if (!wl->dpy)
|
||||
{
|
||||
RARCH_ERR("Failed to connect to Wayland server.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
install_sighandlers();
|
||||
|
||||
wl->registry = wl_display_get_registry(wl->dpy);
|
||||
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
||||
wl_display_roundtrip(wl->dpy);
|
||||
|
||||
if (!wl->compositor)
|
||||
{
|
||||
RARCH_ERR("Failed to create compositor.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!wl->shell)
|
||||
{
|
||||
RARCH_ERR("Failed to create shell.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
wl->fd = wl_display_get_fd(wl->dpy);
|
||||
|
||||
app.pApplicationName = "RetroArch";
|
||||
app.applicationVersion = 0;
|
||||
app.pEngineName = "RetroArch";
|
||||
app.engineVersion = 0;
|
||||
app.apiVersion = VK_API_VERSION;
|
||||
|
||||
info.pApplicationInfo = &app;
|
||||
info.enabledExtensionCount = ARRAY_SIZE(instance_extensions);
|
||||
info.ppEnabledExtensionNames = instance_extensions;
|
||||
|
||||
if (cached_instance)
|
||||
{
|
||||
wl->context.instance = cached_instance;
|
||||
cached_instance = NULL;
|
||||
}
|
||||
else if (vkCreateInstance(&info, NULL, &wl->context.instance) != VK_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (vkEnumeratePhysicalDevices(wl->context.instance, &gpu_count, &wl->context.gpu) != VK_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (gpu_count != 1)
|
||||
{
|
||||
RARCH_ERR("[Wayland/Vulkan]: Failed to enumerate Vulkan physical device.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceProperties(wl->context.gpu, &wl->context.gpu_properties);
|
||||
vkGetPhysicalDeviceMemoryProperties(wl->context.gpu, &wl->context.memory_properties);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(wl->context.gpu, &queue_count, NULL);
|
||||
if (queue_count < 1 || queue_count > 32)
|
||||
goto error;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(wl->context.gpu, &queue_count, queue_properties);
|
||||
|
||||
for (i = 0; i < queue_count; i++)
|
||||
{
|
||||
if (queue_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
wl->context.graphics_queue_index = i;
|
||||
RARCH_LOG("[Wayland/Vulkan]: Device supports %u sub-queues.\n",
|
||||
queue_properties[i].queueCount);
|
||||
found_queue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_queue)
|
||||
{
|
||||
RARCH_ERR("[Wayland/Vulkan]: Did not find suitable graphics queue.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
queue_info.queueFamilyIndex = wl->context.graphics_queue_index;
|
||||
queue_info.queueCount = 1;
|
||||
queue_info.pQueuePriorities = &one;
|
||||
|
||||
device_info.queueCreateInfoCount = 1;
|
||||
device_info.pQueueCreateInfos = &queue_info;
|
||||
device_info.enabledExtensionCount = ARRAY_SIZE(device_extensions);
|
||||
device_info.ppEnabledExtensionNames = device_extensions;
|
||||
device_info.pEnabledFeatures = &features;
|
||||
|
||||
if (cached_device)
|
||||
{
|
||||
wl->context.device = cached_device;
|
||||
cached_device = NULL;
|
||||
video_driver_ctl(RARCH_DISPLAY_CTL_SET_VIDEO_CACHE_CONTEXT_ACK, NULL);
|
||||
RARCH_LOG("[Vulkan]: Using cached Vulkan context.\n");
|
||||
}
|
||||
else if (vkCreateDevice(wl->context.gpu, &device_info, NULL, &wl->context.device) != VK_SUCCESS)
|
||||
goto error;
|
||||
|
||||
vkGetDeviceQueue(wl->context.device, wl->context.graphics_queue_index, 0, &wl->context.queue);
|
||||
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, GetPhysicalDeviceSurfaceSupportKHR);
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, GetPhysicalDeviceSurfaceFormatsKHR);
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, GetPhysicalDeviceSurfacePresentModesKHR);
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, CreateWaylandSurfaceKHR);
|
||||
GET_INSTANCE_PROC_ADDR(wl->context.instance, DestroySurfaceKHR);
|
||||
GET_DEVICE_PROC_ADDR(wl->context.device, CreateSwapchainKHR);
|
||||
GET_DEVICE_PROC_ADDR(wl->context.device, DestroySwapchainKHR);
|
||||
GET_DEVICE_PROC_ADDR(wl->context.device, GetSwapchainImagesKHR);
|
||||
GET_DEVICE_PROC_ADDR(wl->context.device, AcquireNextImageKHR);
|
||||
GET_DEVICE_PROC_ADDR(wl->context.device, QueuePresentKHR);
|
||||
|
||||
wl->context.queue_lock = slock_new();
|
||||
if (!wl->context.queue_lock)
|
||||
goto error;
|
||||
|
||||
return wl;
|
||||
|
||||
error:
|
||||
gfx_ctx_wl_destroy_resources(wl);
|
||||
free(wl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_destroy(void *data)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
if (!wl)
|
||||
return;
|
||||
|
||||
gfx_ctx_wl_destroy_resources(wl);
|
||||
if (wl->context.queue_lock)
|
||||
slock_free(wl->context.queue_lock);
|
||||
free(wl);
|
||||
}
|
||||
|
||||
static void vulkan_acquire_next_image(gfx_ctx_wayland_data_t *wl)
|
||||
{
|
||||
VkResult err;
|
||||
VkSemaphoreCreateInfo sem_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
|
||||
VkFenceCreateInfo info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||
VkFence fence;
|
||||
VkFence *next_fence;
|
||||
unsigned index;
|
||||
|
||||
vkCreateFence(wl->context.device, &info, NULL, &fence);
|
||||
|
||||
err = wl->fpAcquireNextImageKHR(wl->context.device, wl->swapchain, UINT64_MAX,
|
||||
VK_NULL_HANDLE, fence, &wl->context.current_swapchain_index);
|
||||
|
||||
index = wl->context.current_swapchain_index;
|
||||
if (wl->context.swapchain_semaphores[index] == VK_NULL_HANDLE)
|
||||
vkCreateSemaphore(wl->context.device, &sem_info, NULL, &wl->context.swapchain_semaphores[index]);
|
||||
|
||||
vkWaitForFences(wl->context.device, 1, &fence, true, UINT64_MAX);
|
||||
vkDestroyFence(wl->context.device, fence, NULL);
|
||||
|
||||
next_fence = &wl->context.swapchain_fences[index];
|
||||
if (*next_fence != VK_NULL_HANDLE)
|
||||
{
|
||||
vkWaitForFences(wl->context.device, 1, next_fence, true, UINT64_MAX);
|
||||
vkResetFences(wl->context.device, 1, next_fence);
|
||||
}
|
||||
else
|
||||
vkCreateFence(wl->context.device, &info, NULL, next_fence);
|
||||
|
||||
if (err != VK_SUCCESS)
|
||||
{
|
||||
RARCH_LOG("[Wayland/Vulkan]: AcquireNextImage failed, invalidating swapchain.\n");
|
||||
wl->context.invalid_swapchain = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool vulkan_create_swapchain(gfx_ctx_wayland_data_t *wl)
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR surface_properties;
|
||||
VkSurfaceFormatKHR formats[256];
|
||||
VkSurfaceFormatKHR format;
|
||||
VkExtent2D swapchain_size;
|
||||
VkPresentModeKHR swapchain_present_mode = wl->swap_interval ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
VkSurfaceTransformFlagBitsKHR pre_transform;
|
||||
VkSwapchainKHR old_swapchain;
|
||||
VkSwapchainCreateInfoKHR info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
|
||||
uint32_t format_count;
|
||||
uint32_t desired_swapchain_images;
|
||||
unsigned i;
|
||||
|
||||
RARCH_LOG("[Wayland/Vulkan]: Creating swapchain with present mode: %u\n", (unsigned)swapchain_present_mode);
|
||||
|
||||
wl->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(wl->context.gpu, wl->surface, &surface_properties);
|
||||
wl->fpGetPhysicalDeviceSurfaceFormatsKHR(wl->context.gpu, wl->surface, &format_count, NULL);
|
||||
wl->fpGetPhysicalDeviceSurfaceFormatsKHR(wl->context.gpu, wl->surface, &format_count, formats);
|
||||
|
||||
if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
format = formats[0];
|
||||
format.format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (format_count == 0)
|
||||
{
|
||||
RARCH_ERR("[Wayland Vulkan]: Surface has no formats.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
format = formats[0];
|
||||
}
|
||||
|
||||
if (surface_properties.currentExtent.width == -1)
|
||||
{
|
||||
swapchain_size.width = wl->width;
|
||||
swapchain_size.height = wl->height;
|
||||
}
|
||||
else
|
||||
swapchain_size = surface_properties.currentExtent;
|
||||
|
||||
desired_swapchain_images = surface_properties.minImageCount + 1;
|
||||
if ((surface_properties.maxImageCount > 0) && (desired_swapchain_images > surface_properties.maxImageCount))
|
||||
desired_swapchain_images = surface_properties.maxImageCount;
|
||||
|
||||
if (surface_properties.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
|
||||
pre_transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
else
|
||||
pre_transform = surface_properties.currentTransform;
|
||||
|
||||
old_swapchain = wl->swapchain;
|
||||
|
||||
info.surface = wl->surface;
|
||||
info.minImageCount = desired_swapchain_images;
|
||||
info.imageFormat = format.format;
|
||||
info.imageColorSpace = format.colorSpace;
|
||||
info.imageExtent.width = swapchain_size.width;
|
||||
info.imageExtent.height = swapchain_size.height;
|
||||
info.imageArrayLayers = 1;
|
||||
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
info.preTransform = pre_transform;
|
||||
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
info.presentMode = swapchain_present_mode;
|
||||
info.clipped = true;
|
||||
info.oldSwapchain = old_swapchain;
|
||||
|
||||
wl->fpCreateSwapchainKHR(wl->context.device, &info, NULL, &wl->swapchain);
|
||||
if (old_swapchain != VK_NULL_HANDLE)
|
||||
wl->fpDestroySwapchainKHR(wl->context.device, old_swapchain, NULL);
|
||||
|
||||
wl->context.swapchain_width = swapchain_size.width;
|
||||
wl->context.swapchain_height = swapchain_size.height;
|
||||
|
||||
/* Make sure we create a backbuffer format that is as we expect. */
|
||||
switch (format.format)
|
||||
{
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
wl->context.swapchain_format = VK_FORMAT_B8G8R8A8_UNORM;
|
||||
wl->context.swapchain_is_srgb = true;
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
wl->context.swapchain_format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
wl->context.swapchain_is_srgb = true;
|
||||
break;
|
||||
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
wl->context.swapchain_format = VK_FORMAT_R8G8B8_UNORM;
|
||||
wl->context.swapchain_is_srgb = true;
|
||||
break;
|
||||
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
wl->context.swapchain_format = VK_FORMAT_B8G8R8_UNORM;
|
||||
wl->context.swapchain_is_srgb = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
wl->context.swapchain_format = format.format;
|
||||
break;
|
||||
}
|
||||
|
||||
wl->fpGetSwapchainImagesKHR(wl->context.device, wl->swapchain,
|
||||
&wl->context.num_swapchain_images, NULL);
|
||||
wl->fpGetSwapchainImagesKHR(wl->context.device, wl->swapchain,
|
||||
&wl->context.num_swapchain_images, wl->context.swapchain_images);
|
||||
|
||||
for (i = 0; i < wl->context.num_swapchain_images; i++)
|
||||
{
|
||||
if (wl->context.swapchain_fences[i])
|
||||
{
|
||||
vkDestroyFence(wl->context.device, wl->context.swapchain_fences[i], NULL);
|
||||
wl->context.swapchain_fences[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_acquire_next_image(wl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vulkan_present(gfx_ctx_wayland_data_t *wl, unsigned index)
|
||||
{
|
||||
VkResult result = VK_SUCCESS, err = VK_SUCCESS;
|
||||
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
present.swapchainCount = 1;
|
||||
present.pSwapchains = &wl->swapchain;
|
||||
present.pImageIndices = &index;
|
||||
present.pResults = &result;
|
||||
present.waitSemaphoreCount = 1;
|
||||
present.pWaitSemaphores = &wl->context.swapchain_semaphores[index];
|
||||
|
||||
/* Better hope QueuePresent doesn't block D: */
|
||||
slock_lock(wl->context.queue_lock);
|
||||
err = wl->fpQueuePresentKHR(wl->context.queue, &present);
|
||||
if (err != VK_SUCCESS || result != VK_SUCCESS)
|
||||
{
|
||||
RARCH_LOG("[Wayland/Vulkan]: QueuePresent failed, invalidating swapchain.\n");
|
||||
wl->context.invalid_swapchain = true;
|
||||
}
|
||||
slock_unlock(wl->context.queue_lock);
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_swap_buffers(void *data)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
vulkan_present(wl, wl->context.current_swapchain_index);
|
||||
vulkan_acquire_next_image(wl);
|
||||
flush_wayland_fd(wl);
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_set_swap_interval(void *data, unsigned swap_interval)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
if (wl->swap_interval != swap_interval)
|
||||
{
|
||||
wl->swap_interval = swap_interval;
|
||||
if (wl->swapchain)
|
||||
wl->need_new_swapchain = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_set_video_mode(void *data,
|
||||
unsigned width, unsigned height,
|
||||
bool fullscreen)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
VkWaylandSurfaceCreateInfoKHR wl_info = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR };
|
||||
|
||||
wl->width = width ? width : DEFAULT_WINDOWED_WIDTH;
|
||||
wl->height = height ? height : DEFAULT_WINDOWED_HEIGHT;
|
||||
|
||||
/* TODO: Use wl_output::scale to obtain correct value. */
|
||||
wl->buffer_scale = 1;
|
||||
|
||||
wl->surf = wl_compositor_create_surface(wl->compositor);
|
||||
wl_surface_set_buffer_scale(wl->surf, wl->buffer_scale);
|
||||
|
||||
wl->shell_surf = wl_shell_get_shell_surface(wl->shell, wl->surf);
|
||||
|
||||
wl_shell_surface_add_listener(wl->shell_surf, &shell_surface_listener, wl);
|
||||
wl_shell_surface_set_toplevel(wl->shell_surf);
|
||||
wl_shell_surface_set_class(wl->shell_surf, "RetroArch");
|
||||
wl_shell_surface_set_title(wl->shell_surf, "RetroArch");
|
||||
|
||||
if (fullscreen)
|
||||
wl_shell_surface_set_fullscreen(wl->shell_surf, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);
|
||||
|
||||
flush_wayland_fd(wl);
|
||||
wl_display_roundtrip(wl->dpy);
|
||||
|
||||
wl_info.display = wl->dpy;
|
||||
wl_info.surface = wl->surf;
|
||||
|
||||
wl->fpCreateWaylandSurfaceKHR(wl->context.instance, &wl_info, NULL, &wl->surface);
|
||||
|
||||
if (!vulkan_create_swapchain(wl))
|
||||
goto error;
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
gfx_ctx_wl_destroy(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void gfx_ctx_wl_input_driver(void *data,
|
||||
const input_driver_t **input, void **input_data)
|
||||
{
|
||||
(void)data;
|
||||
#if 0
|
||||
void *wl = input_wayland.init();
|
||||
*input = wl ? &input_wayland : NULL;
|
||||
*input_data = wl;
|
||||
#endif
|
||||
*input = NULL;
|
||||
*input_data = NULL;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_has_focus(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_suppress_screensaver(void *data, bool enable)
|
||||
{
|
||||
(void)data;
|
||||
(void)enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_has_windowed(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wl_bind_api(void *video_driver,
|
||||
enum gfx_ctx_api api, unsigned major, unsigned minor)
|
||||
{
|
||||
(void)video_driver;
|
||||
(void)api;
|
||||
(void)major;
|
||||
(void)minor;
|
||||
return api == GFX_CTX_VULKAN_API;
|
||||
}
|
||||
|
||||
static void *gfx_ctx_wl_get_context_data(void *data)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
return &wl->context;
|
||||
}
|
||||
|
||||
const gfx_ctx_driver_t gfx_ctx_wayland_vulkan = {
|
||||
gfx_ctx_wl_init,
|
||||
gfx_ctx_wl_destroy,
|
||||
gfx_ctx_wl_bind_api,
|
||||
gfx_ctx_wl_set_swap_interval,
|
||||
gfx_ctx_wl_set_video_mode,
|
||||
gfx_ctx_wl_get_video_size,
|
||||
NULL, /* get_video_output_size */
|
||||
NULL, /* get_video_output_prev */
|
||||
NULL, /* get_video_output_next */
|
||||
NULL, /* get_metrics */
|
||||
NULL,
|
||||
gfx_ctx_wl_update_window_title,
|
||||
gfx_ctx_wl_check_window,
|
||||
gfx_ctx_wl_set_resize,
|
||||
gfx_ctx_wl_has_focus,
|
||||
gfx_ctx_wl_suppress_screensaver,
|
||||
gfx_ctx_wl_has_windowed,
|
||||
gfx_ctx_wl_swap_buffers,
|
||||
gfx_ctx_wl_input_driver,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"wayland-vulkan",
|
||||
NULL,
|
||||
gfx_ctx_wl_get_context_data,
|
||||
};
|
@ -187,7 +187,7 @@ static void gl_raster_font_free_font(void *data)
|
||||
if (font->font_driver && font->font_data)
|
||||
font->font_driver->free(font->font_data);
|
||||
|
||||
video_driver_texture_unload((uintptr_t*)&font->tex);
|
||||
glDeleteTextures(1, &font->tex);
|
||||
free(font);
|
||||
}
|
||||
|
||||
@ -197,8 +197,8 @@ static int gl_get_message_width(void *data, const char *msg,
|
||||
gl_raster_t *font = (gl_raster_t*)data;
|
||||
|
||||
unsigned i;
|
||||
unsigned msg_len = min(msg_len_full, MAX_MSG_LEN_CHUNK);
|
||||
int delta_x = 0;
|
||||
unsigned msg_len = min(msg_len_full, MAX_MSG_LEN_CHUNK);
|
||||
int delta_x = 0;
|
||||
|
||||
if (!font)
|
||||
return 0;
|
||||
|
355
gfx/drivers_font/vulkan_raster_font.c
Normal file
355
gfx/drivers_font/vulkan_raster_font.c
Normal file
@ -0,0 +1,355 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../common/vulkan_common.h"
|
||||
#include "../font_driver.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vk_t *vk;
|
||||
struct vk_texture texture;
|
||||
const font_renderer_driver_t *font_driver;
|
||||
void *font_data;
|
||||
|
||||
struct vk_vertex *pv;
|
||||
struct vk_buffer_range range;
|
||||
unsigned vertices;
|
||||
} vulkan_raster_t;
|
||||
|
||||
static void vulkan_raster_font_free_font(void *data);
|
||||
|
||||
static void *vulkan_raster_font_init_font(void *data,
|
||||
const char *font_path, float font_size)
|
||||
{
|
||||
const struct font_atlas *atlas = NULL;
|
||||
vulkan_raster_t *font = (vulkan_raster_t*)calloc(1, sizeof(*font));
|
||||
|
||||
VkComponentMapping swizzle = {
|
||||
VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_R,
|
||||
};
|
||||
|
||||
if (!font)
|
||||
return NULL;
|
||||
|
||||
font->vk = (vk_t*)data;
|
||||
|
||||
if (!font_renderer_create_default((const void**)&font->font_driver,
|
||||
&font->font_data, font_path, font_size))
|
||||
{
|
||||
RARCH_WARN("Couldn't initialize font renderer.\n");
|
||||
free(font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
atlas = font->font_driver->get_atlas(font->font_data);
|
||||
font->texture = vulkan_create_texture(font->vk, NULL,
|
||||
atlas->width, atlas->height, VK_FORMAT_R8_UNORM, atlas->buffer, &swizzle, VULKAN_TEXTURE_STATIC);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_free_font(void *data)
|
||||
{
|
||||
vulkan_raster_t *font = (vulkan_raster_t*)data;
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
if (font->font_driver && font->font_data)
|
||||
font->font_driver->free(font->font_data);
|
||||
|
||||
vkQueueWaitIdle(font->vk->context->queue);
|
||||
vulkan_destroy_texture(font->vk->context->device, &font->texture);
|
||||
|
||||
free(font);
|
||||
}
|
||||
|
||||
static int vulkan_get_message_width(void *data, const char *msg, unsigned msg_len, float scale)
|
||||
{
|
||||
vulkan_raster_t *font = (vulkan_raster_t*)data;
|
||||
|
||||
unsigned i;
|
||||
int delta_x = 0;
|
||||
|
||||
if (!font)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < msg_len; i++)
|
||||
{
|
||||
const struct font_glyph *glyph =
|
||||
font->font_driver->get_glyph(font->font_data, (uint8_t)msg[i]);
|
||||
if (!glyph) /* Do something smarter here ... */
|
||||
glyph = font->font_driver->get_glyph(font->font_data, '?');
|
||||
if (!glyph)
|
||||
continue;
|
||||
|
||||
delta_x += glyph->advance_x;
|
||||
}
|
||||
|
||||
return delta_x * scale;
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_render_line(
|
||||
vulkan_raster_t *font, const char *msg, unsigned msg_len,
|
||||
float scale, const float color[4], float pos_x,
|
||||
float pos_y, unsigned text_align)
|
||||
{
|
||||
int x, y, delta_x, delta_y;
|
||||
float inv_tex_size_x, inv_tex_size_y, inv_win_width, inv_win_height;
|
||||
unsigned i;
|
||||
struct vk_color vk_color;
|
||||
vk_t *vk = font ? font->vk : NULL;
|
||||
|
||||
if (!vk)
|
||||
return;
|
||||
|
||||
x = roundf(pos_x * vk->vp.width);
|
||||
y = roundf((1.0f - pos_y) * vk->vp.height);
|
||||
delta_x = 0;
|
||||
delta_y = 0;
|
||||
|
||||
vk_color.r = color[0];
|
||||
vk_color.g = color[1];
|
||||
vk_color.b = color[2];
|
||||
vk_color.a = color[3];
|
||||
|
||||
switch (text_align)
|
||||
{
|
||||
case TEXT_ALIGN_RIGHT:
|
||||
x -= vulkan_get_message_width(font, msg, msg_len, scale);
|
||||
break;
|
||||
case TEXT_ALIGN_CENTER:
|
||||
x -= vulkan_get_message_width(font, msg, msg_len, scale) / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
inv_tex_size_x = 1.0f / font->texture.width;
|
||||
inv_tex_size_y = 1.0f / font->texture.height;
|
||||
inv_win_width = 1.0f / font->vk->vp.width;
|
||||
inv_win_height = 1.0f / font->vk->vp.height;
|
||||
|
||||
for (i = 0; i < msg_len; i++)
|
||||
{
|
||||
int off_x, off_y, tex_x, tex_y, width, height;
|
||||
const struct font_glyph *glyph =
|
||||
font->font_driver->get_glyph(font->font_data, (uint8_t)msg[i]);
|
||||
|
||||
if (!glyph) /* Do something smarter here ... */
|
||||
glyph = font->font_driver->get_glyph(font->font_data, '?');
|
||||
if (!glyph)
|
||||
continue;
|
||||
|
||||
off_x = glyph->draw_offset_x;
|
||||
off_y = glyph->draw_offset_y;
|
||||
tex_x = glyph->atlas_offset_x;
|
||||
tex_y = glyph->atlas_offset_y;
|
||||
width = glyph->width;
|
||||
height = glyph->height;
|
||||
|
||||
vulkan_write_quad_vbo(font->pv + font->vertices,
|
||||
(x + off_x + delta_x * scale) * inv_win_width, (y + off_y + delta_y * scale) * inv_win_height,
|
||||
width * scale * inv_win_width, height * scale * inv_win_height,
|
||||
tex_x * inv_tex_size_x, tex_y * inv_tex_size_y,
|
||||
width * inv_tex_size_x, height * inv_tex_size_y,
|
||||
&vk_color);
|
||||
font->vertices += 6;
|
||||
|
||||
delta_x += glyph->advance_x;
|
||||
delta_y += glyph->advance_y;
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_render_message(
|
||||
vulkan_raster_t *font, const char *msg, float scale,
|
||||
const float color[4], float pos_x, float pos_y,
|
||||
unsigned text_align)
|
||||
{
|
||||
int lines = 0;
|
||||
float line_height;
|
||||
|
||||
if (!msg || !*msg || !font->vk)
|
||||
return;
|
||||
|
||||
/* If the font height is not supported just draw as usual */
|
||||
if (!font->font_driver->get_line_height)
|
||||
{
|
||||
vulkan_raster_font_render_line(font, msg, strlen(msg), scale, color, pos_x, pos_y, text_align);
|
||||
return;
|
||||
}
|
||||
|
||||
line_height = scale / font->font_driver->get_line_height(font->font_data);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char *delim = strchr(msg, '\n');
|
||||
|
||||
/* Draw the line */
|
||||
if (delim)
|
||||
{
|
||||
unsigned msg_len = delim - msg;
|
||||
vulkan_raster_font_render_line(font, msg, msg_len, scale, color, pos_x, pos_y - (float)lines * line_height, text_align);
|
||||
msg += msg_len + 1;
|
||||
lines++;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned msg_len = strlen(msg);
|
||||
vulkan_raster_font_render_line(font, msg, msg_len, scale, color, pos_x, pos_y - (float)lines * line_height, text_align);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_setup_viewport(vulkan_raster_t *font, bool full_screen)
|
||||
{
|
||||
unsigned width, height;
|
||||
video_driver_get_size(&width, &height);
|
||||
video_driver_set_viewport(width, height, full_screen, false);
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_flush(vulkan_raster_t *font)
|
||||
{
|
||||
const struct vk_draw_triangles call = {
|
||||
font->vk->pipelines.alpha_blend,
|
||||
&font->texture,
|
||||
font->vk->samplers.nearest,
|
||||
&font->vk->mvp,
|
||||
&font->range,
|
||||
font->vertices,
|
||||
};
|
||||
|
||||
vulkan_draw_triangles(font->vk, &call);
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_render_msg(void *data, const char *msg,
|
||||
const void *userdata)
|
||||
{
|
||||
float x, y, scale, drop_mod;
|
||||
float color[4], color_dark[4];
|
||||
int drop_x, drop_y;
|
||||
bool full_screen;
|
||||
enum text_alignment text_align;
|
||||
vk_t *vk = NULL;
|
||||
vulkan_raster_t *font = (vulkan_raster_t*)data;
|
||||
settings_t *settings = config_get_ptr();
|
||||
const struct font_params *params = (const struct font_params*)userdata;
|
||||
unsigned max_glyphs;
|
||||
|
||||
if (!font || !msg || !*msg)
|
||||
return;
|
||||
|
||||
vk = font->vk;
|
||||
|
||||
if (params)
|
||||
{
|
||||
x = params->x;
|
||||
y = params->y;
|
||||
scale = params->scale;
|
||||
full_screen = params->full_screen;
|
||||
text_align = params->text_align;
|
||||
drop_x = params->drop_x;
|
||||
drop_y = params->drop_y;
|
||||
drop_mod = params->drop_mod;
|
||||
|
||||
color[0] = FONT_COLOR_GET_RED(params->color) / 255.0f;
|
||||
color[1] = FONT_COLOR_GET_GREEN(params->color) / 255.0f;
|
||||
color[2] = FONT_COLOR_GET_BLUE(params->color) / 255.0f;
|
||||
color[3] = FONT_COLOR_GET_ALPHA(params->color) / 255.0f;
|
||||
|
||||
/* If alpha is 0.0f, turn it into default 1.0f */
|
||||
if (color[3] <= 0.0f)
|
||||
color[3] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = settings->video.msg_pos_x;
|
||||
y = settings->video.msg_pos_y;
|
||||
scale = 1.0f;
|
||||
full_screen = true;
|
||||
text_align = TEXT_ALIGN_LEFT;
|
||||
|
||||
color[0] = settings->video.msg_color_r;
|
||||
color[1] = settings->video.msg_color_g;
|
||||
color[2] = settings->video.msg_color_b;
|
||||
color[3] = 1.0f;
|
||||
|
||||
drop_x = -2;
|
||||
drop_y = -2;
|
||||
drop_mod = 0.3f;
|
||||
}
|
||||
|
||||
vulkan_raster_font_setup_viewport(font, full_screen);
|
||||
|
||||
max_glyphs = strlen(msg);
|
||||
if (drop_x || drop_y)
|
||||
max_glyphs *= 2;
|
||||
|
||||
if (!vulkan_buffer_chain_alloc(font->vk->context, &font->vk->chain->vbo,
|
||||
6 * sizeof(struct vk_vertex) * max_glyphs, &font->range))
|
||||
return;
|
||||
|
||||
font->vertices = 0;
|
||||
font->pv = (struct vk_vertex*)font->range.data;
|
||||
|
||||
if (drop_x || drop_y)
|
||||
{
|
||||
color_dark[0] = color[0] * drop_mod;
|
||||
color_dark[1] = color[1] * drop_mod;
|
||||
color_dark[2] = color[2] * drop_mod;
|
||||
color_dark[3] = color[3];
|
||||
|
||||
vulkan_raster_font_render_message(font, msg, scale, color_dark,
|
||||
x + scale * drop_x / vk->vp.width, y +
|
||||
scale * drop_y / vk->vp.height, text_align);
|
||||
}
|
||||
|
||||
vulkan_raster_font_render_message(font, msg, scale, color, x, y, text_align);
|
||||
vulkan_raster_font_flush(font);
|
||||
}
|
||||
|
||||
static const struct font_glyph *vulkan_raster_font_get_glyph(
|
||||
void *data, uint32_t code)
|
||||
{
|
||||
vulkan_raster_t *font = (vulkan_raster_t*)data;
|
||||
|
||||
if (!font || !font->font_driver)
|
||||
return NULL;
|
||||
if (!font->font_driver->ident)
|
||||
return NULL;
|
||||
return font->font_driver->get_glyph((void*)font->font_driver, code);
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_flush_block(void *data)
|
||||
{
|
||||
(void)data;
|
||||
}
|
||||
|
||||
static void vulkan_raster_font_bind_block(void *data, void *userdata)
|
||||
{
|
||||
(void)data;
|
||||
}
|
||||
|
||||
font_renderer_t vulkan_raster_font = {
|
||||
vulkan_raster_font_init_font,
|
||||
vulkan_raster_font_free_font,
|
||||
vulkan_raster_font_render_msg,
|
||||
"Vulkan raster",
|
||||
vulkan_raster_font_get_glyph,
|
||||
vulkan_raster_font_bind_block,
|
||||
vulkan_raster_font_flush_block,
|
||||
vulkan_get_message_width
|
||||
};
|
123
gfx/drivers_shader/glslang_util.cpp
Normal file
123
gfx/drivers_shader/glslang_util.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "glslang_util.hpp"
|
||||
#include "glslang.hpp"
|
||||
|
||||
#include "../../general.h"
|
||||
#include "libretro-common/include/retro_file.h"
|
||||
#include "libretro-common/include/string/string_list.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool read_file(const char *path, vector<string> *output)
|
||||
{
|
||||
char *buf = nullptr;
|
||||
ssize_t len = 0;
|
||||
if (retro_read_file(path, (void**)&buf, &len) < 0)
|
||||
{
|
||||
RARCH_ERR("Failed to open shader file: \"%s\".\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct string_list *list = string_split(buf, "\n");
|
||||
if (!list)
|
||||
{
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (list->size == 0)
|
||||
{
|
||||
free(buf);
|
||||
string_list_free(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
output->clear();
|
||||
for (size_t i = 0; i < list->size; i++)
|
||||
output->push_back(list->elems[i].data);
|
||||
|
||||
string_list_free(list);
|
||||
return true;
|
||||
}
|
||||
|
||||
string build_stage_source(const vector<string> &lines, const char *stage)
|
||||
{
|
||||
ostringstream str;
|
||||
|
||||
// Version header.
|
||||
str << lines.front();
|
||||
str << '\n';
|
||||
bool active = true;
|
||||
|
||||
for (auto itr = begin(lines) + 1; itr != end(lines); ++itr)
|
||||
{
|
||||
if (itr->find("#pragma stage ") != string::npos)
|
||||
{
|
||||
auto expected = string("#pragma stage ") + stage;
|
||||
active = itr->find(expected) != string::npos;
|
||||
|
||||
// Improve debuggability.
|
||||
if (active)
|
||||
{
|
||||
str << "#line ";
|
||||
str << (itr - begin(lines)) + 2;
|
||||
str << '\n';
|
||||
}
|
||||
}
|
||||
else if (active)
|
||||
str << *itr;
|
||||
str << '\n';
|
||||
}
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
bool glslang_compile_shader(const char *shader_path, glslang_output *output)
|
||||
{
|
||||
RARCH_LOG("Compiling shader \"%s\".\n", shader_path);
|
||||
vector<string> lines;
|
||||
if (!read_file(shader_path, &lines))
|
||||
return false;
|
||||
|
||||
auto &header = lines.front();
|
||||
if (header.find_first_of("#version ") == string::npos)
|
||||
{
|
||||
RARCH_ERR("First line of the shader must contain a valid #version string.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glslang::compile_spirv(build_stage_source(lines, "vertex"),
|
||||
glslang::StageVertex, &output->vertex))
|
||||
{
|
||||
RARCH_ERR("Failed to compile vertex shader stage.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!glslang::compile_spirv(build_stage_source(lines, "fragment"),
|
||||
glslang::StageFragment, &output->fragment))
|
||||
{
|
||||
RARCH_ERR("Failed to compile fragment shader stage.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
32
gfx/drivers_shader/glslang_util.hpp
Normal file
32
gfx/drivers_shader/glslang_util.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GLSLANG_UTIL_HPP
|
||||
#define GLSLANG_UTIL_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
struct glslang_output
|
||||
{
|
||||
std::vector<uint32_t> vertex;
|
||||
std::vector<uint32_t> fragment;
|
||||
};
|
||||
|
||||
bool glslang_compile_shader(const char *shader_path, glslang_output *output);
|
||||
|
||||
|
||||
#endif
|
||||
|
1492
gfx/drivers_shader/shader_vulkan.cpp
Normal file
1492
gfx/drivers_shader/shader_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load Diff
133
gfx/drivers_shader/shader_vulkan.h
Normal file
133
gfx/drivers_shader/shader_vulkan.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2016 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SHADER_VULKAN_H
|
||||
#define SHADER_VULKAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "libretro-common/include/boolean.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct vulkan_filter_chain vulkan_filter_chain_t;
|
||||
|
||||
enum vulkan_filter_chain_filter
|
||||
{
|
||||
VULKAN_FILTER_CHAIN_LINEAR = 0,
|
||||
VULKAN_FILTER_CHAIN_NEAREST = 1
|
||||
};
|
||||
|
||||
struct vulkan_filter_chain_texture
|
||||
{
|
||||
VkImageView view;
|
||||
VkImageLayout layout;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
enum vulkan_filter_chain_scale
|
||||
{
|
||||
VULKAN_FILTER_CHAIN_SCALE_ORIGINAL,
|
||||
VULKAN_FILTER_CHAIN_SCALE_SOURCE,
|
||||
VULKAN_FILTER_CHAIN_SCALE_VIEWPORT,
|
||||
VULKAN_FILTER_CHAIN_SCALE_ABSOLUTE
|
||||
};
|
||||
|
||||
struct vulkan_filter_chain_pass_info
|
||||
{
|
||||
/* For the last pass, make sure VIEWPORT scale with scale factors of 1 are used. */
|
||||
enum vulkan_filter_chain_scale scale_type_x;
|
||||
enum vulkan_filter_chain_scale scale_type_y;
|
||||
float scale_x;
|
||||
float scale_y;
|
||||
|
||||
/* Ignored for the last pass, swapchain info will be used instead. */
|
||||
VkFormat rt_format;
|
||||
|
||||
/* The filter to use for source in this pass. */
|
||||
enum vulkan_filter_chain_filter source_filter;
|
||||
};
|
||||
|
||||
struct vulkan_filter_chain_swapchain_info
|
||||
{
|
||||
VkViewport viewport;
|
||||
VkFormat format;
|
||||
VkRenderPass render_pass;
|
||||
unsigned num_indices;
|
||||
};
|
||||
|
||||
struct vulkan_filter_chain_create_info
|
||||
{
|
||||
VkDevice device;
|
||||
const VkPhysicalDeviceMemoryProperties *memory_properties;
|
||||
VkPipelineCache pipeline_cache;
|
||||
unsigned num_passes;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned width, height;
|
||||
} max_input_size;
|
||||
struct vulkan_filter_chain_swapchain_info swapchain;
|
||||
};
|
||||
|
||||
vulkan_filter_chain_t *vulkan_filter_chain_new(
|
||||
const struct vulkan_filter_chain_create_info *info);
|
||||
void vulkan_filter_chain_free(vulkan_filter_chain_t *chain);
|
||||
|
||||
void vulkan_filter_chain_set_shader(vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
VkShaderStageFlags stage,
|
||||
const uint32_t *spirv,
|
||||
size_t spirv_words);
|
||||
|
||||
void vulkan_filter_chain_set_pass_info(vulkan_filter_chain_t *chain,
|
||||
unsigned pass,
|
||||
const struct vulkan_filter_chain_pass_info *info);
|
||||
|
||||
bool vulkan_filter_chain_update_swapchain_info(vulkan_filter_chain_t *chain,
|
||||
const struct vulkan_filter_chain_swapchain_info *info);
|
||||
|
||||
void vulkan_filter_chain_notify_sync_index(vulkan_filter_chain_t *chain,
|
||||
unsigned index);
|
||||
|
||||
bool vulkan_filter_chain_init(vulkan_filter_chain_t *chain);
|
||||
|
||||
void vulkan_filter_chain_set_input_texture(vulkan_filter_chain_t *chain,
|
||||
const struct vulkan_filter_chain_texture *texture);
|
||||
|
||||
void vulkan_filter_chain_build_offscreen_passes(vulkan_filter_chain_t *chain,
|
||||
VkCommandBuffer cmd, const VkViewport *vp);
|
||||
void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain,
|
||||
VkCommandBuffer cmd, const VkViewport *vp, const float *mvp);
|
||||
|
||||
vulkan_filter_chain_t *vulkan_filter_chain_create_default(const struct vulkan_filter_chain_create_info *info,
|
||||
enum vulkan_filter_chain_filter filter);
|
||||
|
||||
vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulkan_filter_chain_create_info *info,
|
||||
const char *path, enum vulkan_filter_chain_filter filter);
|
||||
|
||||
struct video_shader *vulkan_filter_chain_get_preset(vulkan_filter_chain_t *chain);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -140,6 +140,34 @@ static bool gl_font_init_first(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
static const font_renderer_t *vulkan_font_backends[] = {
|
||||
&vulkan_raster_font,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static bool vulkan_font_init_first(
|
||||
const void **font_driver, void **font_handle,
|
||||
void *video_data, const char *font_path, float font_size)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; vulkan_font_backends[i]; i++)
|
||||
{
|
||||
void *data = vulkan_font_backends[i]->init(video_data, font_path, font_size);
|
||||
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
*font_driver = vulkan_font_backends[i];
|
||||
*font_handle = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VITA2D
|
||||
static const font_renderer_t *vita2d_font_backends[] = {
|
||||
&vita2d_vita_font
|
||||
@ -188,6 +216,11 @@ static bool font_init_first(
|
||||
return gl_font_init_first(font_driver, font_handle,
|
||||
video_data, font_path, font_size);
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
case FONT_DRIVER_RENDER_VULKAN_API:
|
||||
return vulkan_font_init_first(font_driver, font_handle,
|
||||
video_data, font_path, font_size);
|
||||
#endif
|
||||
#ifdef HAVE_VITA2D
|
||||
case FONT_DRIVER_RENDER_VITA2D:
|
||||
return vita2d_font_init_first(font_driver, font_handle,
|
||||
|
@ -30,7 +30,8 @@ enum font_driver_render_api
|
||||
FONT_DRIVER_RENDER_DONT_CARE,
|
||||
FONT_DRIVER_RENDER_OPENGL_API,
|
||||
FONT_DRIVER_RENDER_DIRECT3D_API,
|
||||
FONT_DRIVER_RENDER_VITA2D
|
||||
FONT_DRIVER_RENDER_VITA2D,
|
||||
FONT_DRIVER_RENDER_VULKAN_API
|
||||
};
|
||||
|
||||
enum text_alignment
|
||||
@ -149,6 +150,7 @@ extern font_renderer_t d3d_xbox360_font;
|
||||
extern font_renderer_t d3d_xdk1_font;
|
||||
extern font_renderer_t d3d_win32_font;
|
||||
extern font_renderer_t vita2d_vita_font;
|
||||
extern font_renderer_t vulkan_raster_font;
|
||||
|
||||
extern font_renderer_driver_t stb_font_renderer;
|
||||
extern font_renderer_driver_t freetype_font_renderer;
|
||||
|
@ -52,6 +52,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
|
||||
#if defined(HAVE_WAYLAND) && defined(HAVE_OPENGL) && defined(HAVE_EGL)
|
||||
&gfx_ctx_wayland,
|
||||
#endif
|
||||
#if defined(HAVE_WAYLAND) && defined(HAVE_VULKAN)
|
||||
&gfx_ctx_wayland_vulkan,
|
||||
#endif
|
||||
#if defined(HAVE_X11) && defined(HAVE_OPENGL) && defined(HAVE_EGL)
|
||||
&gfx_ctx_x_egl,
|
||||
#endif
|
||||
@ -433,6 +436,13 @@ bool gfx_ctx_ctl(enum gfx_ctx_ctl_state state, void *data)
|
||||
current_video_context->get_video_size(video_context_data, &mode_info->width, &mode_info->height);
|
||||
}
|
||||
break;
|
||||
case GFX_CTL_GET_CONTEXT_DATA:
|
||||
{
|
||||
if (!current_video_context || !current_video_context->get_context_data)
|
||||
return false;
|
||||
*(void**)data = current_video_context->get_context_data(video_context_data);
|
||||
}
|
||||
break;
|
||||
case GFX_CTL_SET_VIDEO_CONTEXT_DATA:
|
||||
video_context_data = data;
|
||||
break;
|
||||
|
@ -40,7 +40,8 @@ enum gfx_ctx_api
|
||||
GFX_CTX_OPENGL_ES_API,
|
||||
GFX_CTX_DIRECT3D8_API,
|
||||
GFX_CTX_DIRECT3D9_API,
|
||||
GFX_CTX_OPENVG_API
|
||||
GFX_CTX_OPENVG_API,
|
||||
GFX_CTX_VULKAN_API
|
||||
};
|
||||
|
||||
enum display_metric_types
|
||||
@ -83,7 +84,8 @@ enum gfx_ctx_ctl_state
|
||||
GFX_CTL_SET_VIDEO_MODE,
|
||||
GFX_CTL_SET_RESIZE,
|
||||
GFX_CTL_GET_VIDEO_SIZE,
|
||||
GFX_CTL_SET_VIDEO_CONTEXT_DATA
|
||||
GFX_CTL_SET_VIDEO_CONTEXT_DATA,
|
||||
GFX_CTL_GET_CONTEXT_DATA
|
||||
};
|
||||
|
||||
typedef void (*gfx_ctx_proc_t)(void);
|
||||
@ -182,6 +184,11 @@ typedef struct gfx_ctx_driver
|
||||
|
||||
/* Optional. Binds HW-render offscreen context. */
|
||||
void (*bind_hw_render)(void *data, bool enable);
|
||||
|
||||
/* Optional. Gets base data for the context which is used by the driver.
|
||||
* This is mostly relevant for graphics APIs such as Vulkan
|
||||
* which do not have global context state. */
|
||||
void *(*get_context_data)(void *data);
|
||||
} gfx_ctx_driver_t;
|
||||
|
||||
typedef struct gfx_ctx_size
|
||||
@ -243,6 +250,7 @@ typedef struct gfx_ctx_ident
|
||||
extern const gfx_ctx_driver_t gfx_ctx_sdl_gl;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_x_egl;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_wayland;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_wayland_vulkan;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_glx;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_d3d;
|
||||
extern const gfx_ctx_driver_t gfx_ctx_drm_egl;
|
||||
|
@ -145,6 +145,9 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = {
|
||||
};
|
||||
|
||||
static const video_driver_t *video_drivers[] = {
|
||||
#ifdef HAVE_VULKAN
|
||||
&video_vulkan,
|
||||
#endif
|
||||
#ifdef HAVE_OPENGL
|
||||
&video_gl,
|
||||
#endif
|
||||
@ -239,18 +242,57 @@ const char* config_get_video_driver_options(void)
|
||||
return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL);
|
||||
}
|
||||
|
||||
static bool hw_render_context_is_vulkan(enum retro_hw_context_type type)
|
||||
{
|
||||
return type == RETRO_HW_CONTEXT_VULKAN;
|
||||
}
|
||||
|
||||
static bool hw_render_context_is_gl(enum retro_hw_context_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RETRO_HW_CONTEXT_OPENGL:
|
||||
case RETRO_HW_CONTEXT_OPENGLES2:
|
||||
case RETRO_HW_CONTEXT_OPENGL_CORE:
|
||||
case RETRO_HW_CONTEXT_OPENGLES3:
|
||||
case RETRO_HW_CONTEXT_OPENGLES_VERSION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool find_video_driver(void)
|
||||
{
|
||||
int i;
|
||||
driver_ctx_info_t drv;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
#if defined(HAVE_OPENGL) && defined(HAVE_FBO)
|
||||
#if (defined(HAVE_OPENGL) && defined(HAVE_FBO)) || defined(HAVE_VULKAN)
|
||||
if (video_driver_ctl(RARCH_DISPLAY_CTL_IS_HW_CONTEXT, NULL))
|
||||
{
|
||||
RARCH_LOG("Using HW render, OpenGL driver forced.\n");
|
||||
current_video = &video_gl;
|
||||
return true;
|
||||
struct retro_hw_render_callback *hwr =
|
||||
video_driver_callback();
|
||||
current_video = NULL;
|
||||
|
||||
#if defined(HAVE_VULKAN)
|
||||
if (hwr && hw_render_context_is_vulkan(hwr->context_type))
|
||||
{
|
||||
RARCH_LOG("Using HW render, Vulkan driver forced.\n");
|
||||
current_video = &video_vulkan;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_OPENGL) && defined(HAVE_FBO)
|
||||
if (hwr && hw_render_context_is_gl(hwr->context_type))
|
||||
{
|
||||
RARCH_LOG("Using HW render, OpenGL driver forced.\n");
|
||||
current_video = &video_gl;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (current_video)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -557,11 +599,17 @@ static bool uninit_video_input(void)
|
||||
|
||||
static bool init_video_pixel_converter(unsigned size)
|
||||
{
|
||||
struct retro_hw_render_callback *hwr = video_driver_callback();
|
||||
|
||||
/* If pixel format is not 0RGB1555, we don't need to do
|
||||
* any internal pixel conversion. */
|
||||
if (video_driver_get_pixel_format() != RETRO_PIXEL_FORMAT_0RGB1555)
|
||||
return true;
|
||||
|
||||
/* No need to perform pixel conversion for HW rendering contexts. */
|
||||
if (hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE)
|
||||
return true;
|
||||
|
||||
RARCH_WARN("0RGB1555 pixel format is deprecated, and will be slower. For 15/16-bit, RGB565 format is preferred.\n");
|
||||
|
||||
video_driver_scaler_ptr = (video_pixel_scaler_t*)
|
||||
@ -1722,6 +1770,13 @@ bool video_driver_ctl(enum rarch_display_ctl_state state, void *data)
|
||||
return false;
|
||||
return video_driver_poke->get_current_software_framebuffer(
|
||||
video_driver_data, (struct retro_framebuffer *)data);
|
||||
case RARCH_DISPLAY_CTL_GET_HW_RENDER_INTERFACE:
|
||||
if (
|
||||
!video_driver_poke ||
|
||||
!video_driver_poke->get_hw_render_interface)
|
||||
return false;
|
||||
return video_driver_poke->get_hw_render_interface(video_driver_data,
|
||||
(const struct retro_hw_render_interface**)data);
|
||||
case RARCH_DISPLAY_CTL_VIEWPORT_INFO:
|
||||
if (!current_video || !current_video->viewport_info)
|
||||
return false;
|
||||
@ -1978,7 +2033,7 @@ uintptr_t video_driver_window_get(void)
|
||||
|
||||
bool video_driver_texture_load(void *data,
|
||||
enum texture_filter_type filter_type,
|
||||
unsigned *id)
|
||||
uintptr_t *id)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
settings_t *settings = config_get_ptr();
|
||||
@ -2004,7 +2059,7 @@ bool video_driver_texture_unload(uintptr_t *id)
|
||||
if (!video_driver_poke || !video_driver_poke->unload_texture)
|
||||
return false;
|
||||
|
||||
video_driver_poke->unload_texture(video_driver_data, id);
|
||||
|
||||
video_driver_poke->unload_texture(video_driver_data, *id);
|
||||
*id = 0;
|
||||
return true;
|
||||
}
|
||||
|
@ -157,6 +157,7 @@ enum rarch_display_ctl_state
|
||||
RARCH_DISPLAY_CTL_GPU_RECORD_INIT,
|
||||
RARCH_DISPLAY_CTL_GPU_RECORD_DEINIT,
|
||||
RARCH_DISPLAY_CTL_GET_CURRENT_SOFTWARE_FRAMEBUFFER,
|
||||
RARCH_DISPLAY_CTL_GET_HW_RENDER_INTERFACE,
|
||||
RARCH_DISPLAY_CTL_VIEWPORT_INFO
|
||||
};
|
||||
|
||||
@ -197,9 +198,8 @@ typedef struct video_poke_interface
|
||||
{
|
||||
uintptr_t (*load_texture)(void *video_data, void *data,
|
||||
bool threaded, enum texture_filter_type filter_type);
|
||||
void (*unload_texture)(void *data, uintptr_t *id);
|
||||
void (*set_video_mode)(void *data, unsigned width,
|
||||
unsigned height, bool fullscreen);
|
||||
void (*unload_texture)(void *data, uintptr_t id);
|
||||
void (*set_video_mode)(void *data, unsigned width, unsigned height, bool fullscreen);
|
||||
void (*set_filtering)(void *data, unsigned index, bool smooth);
|
||||
void (*get_video_output_size)(void *data,
|
||||
unsigned *width, unsigned *height);
|
||||
@ -226,6 +226,8 @@ typedef struct video_poke_interface
|
||||
struct video_shader *(*get_current_shader)(void *data);
|
||||
bool (*get_current_software_framebuffer)(void *data,
|
||||
struct retro_framebuffer *framebuffer);
|
||||
bool (*get_hw_render_interface)(void *data,
|
||||
const struct retro_hw_render_interface **iface);
|
||||
} video_poke_interface_t;
|
||||
|
||||
typedef struct video_viewport
|
||||
@ -534,7 +536,7 @@ void video_driver_window_set(uintptr_t idx);
|
||||
|
||||
bool video_driver_texture_load(void *data,
|
||||
enum texture_filter_type filter_type,
|
||||
unsigned *id);
|
||||
uintptr_t *id);
|
||||
|
||||
bool video_driver_texture_unload(uintptr_t *id);
|
||||
|
||||
@ -549,6 +551,7 @@ void gl_load_texture_data(uint32_t id,
|
||||
#endif
|
||||
|
||||
extern video_driver_t video_gl;
|
||||
extern video_driver_t video_vulkan;
|
||||
extern video_driver_t video_psp1;
|
||||
extern video_driver_t video_vita2d;
|
||||
extern video_driver_t video_ctr;
|
||||
|
@ -923,6 +923,8 @@ enum rarch_shader_type video_shader_parse_type(const char *path,
|
||||
return RARCH_SHADER_CG;
|
||||
else if (string_is_equal(ext, "glslp") || string_is_equal(ext, "glsl"))
|
||||
return RARCH_SHADER_GLSL;
|
||||
else if (string_is_equal(ext, "slangp") || string_is_equal(ext, "slang"))
|
||||
return RARCH_SHADER_SLANG;
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ enum rarch_shader_type
|
||||
RARCH_SHADER_NONE = 0,
|
||||
RARCH_SHADER_CG,
|
||||
RARCH_SHADER_HLSL,
|
||||
RARCH_SHADER_GLSL
|
||||
RARCH_SHADER_GLSL,
|
||||
RARCH_SHADER_SLANG
|
||||
};
|
||||
|
||||
enum gfx_scale_type
|
||||
|
@ -1146,7 +1146,7 @@ static uintptr_t thread_load_texture(void *video_data, void *data,
|
||||
return thr->poke->load_texture(thr->driver_data, data, threaded, filter_type);
|
||||
}
|
||||
|
||||
static void thread_unload_texture(void *video_data, uintptr_t *id)
|
||||
static void thread_unload_texture(void *video_data, uintptr_t id)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)video_data;
|
||||
|
||||
|
42
libretro.h
42
libretro.h
@ -921,6 +921,31 @@ enum retro_mod
|
||||
* writeable (and readable).
|
||||
*/
|
||||
|
||||
enum retro_hw_render_interface_type
|
||||
{
|
||||
RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
|
||||
RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
/* Base struct. All retro_hw_render_interface_* types
|
||||
* contain at least these fields. */
|
||||
struct retro_hw_render_interface
|
||||
{
|
||||
enum retro_hw_render_interface_type interface_type;
|
||||
unsigned interface_version;
|
||||
};
|
||||
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
|
||||
/* const struct retro_hw_render_interface ** --
|
||||
* Returns an API specific rendering interface for accessing API specific data.
|
||||
* Not all HW rendering APIs support or need this.
|
||||
* The contents of the returned pointer is specific to the rendering API
|
||||
* being used. See the various headers like libretro_vulkan.h, etc.
|
||||
*
|
||||
* GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
|
||||
* Similarly, after context_destroyed callback returns,
|
||||
* the contents of the HW_RENDER_INTERFACE are invalidated.
|
||||
*/
|
||||
|
||||
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
|
||||
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
|
||||
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
|
||||
@ -1537,6 +1562,9 @@ enum retro_hw_context_type
|
||||
* use the corresponding enums directly. */
|
||||
RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
|
||||
|
||||
/* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
|
||||
RETRO_HW_CONTEXT_VULKAN = 6,
|
||||
|
||||
RETRO_HW_CONTEXT_DUMMY = INT_MAX
|
||||
};
|
||||
|
||||
@ -1559,23 +1587,28 @@ struct retro_hw_render_callback
|
||||
*/
|
||||
retro_hw_context_reset_t context_reset;
|
||||
|
||||
/* Set by frontend. */
|
||||
/* Set by frontend.
|
||||
* TODO: This is rather obsolete. The frontend should not
|
||||
* be providing preallocated framebuffers. */
|
||||
retro_hw_get_current_framebuffer_t get_current_framebuffer;
|
||||
|
||||
/* Set by frontend. */
|
||||
retro_hw_get_proc_address_t get_proc_address;
|
||||
|
||||
/* Set if render buffers should have depth component attached. */
|
||||
/* Set if render buffers should have depth component attached.
|
||||
* TODO: Obsolete. */
|
||||
bool depth;
|
||||
|
||||
/* Set if stencil buffers should be attached. */
|
||||
/* Set if stencil buffers should be attached.
|
||||
* TODO: Obsolete. */
|
||||
bool stencil;
|
||||
|
||||
/* If depth and stencil are true, a packed 24/8 buffer will be added.
|
||||
* Only attaching stencil is invalid and will be ignored. */
|
||||
|
||||
/* Use conventional bottom-left origin convention. If false,
|
||||
* standard libretro top-left origin semantics are used. */
|
||||
* standard libretro top-left origin semantics are used.
|
||||
* TODO: Move to GL specific interface. */
|
||||
bool bottom_left_origin;
|
||||
|
||||
/* Major version number for core GL context or GLES 3.1+. */
|
||||
@ -1586,6 +1619,7 @@ struct retro_hw_render_callback
|
||||
|
||||
/* If this is true, the frontend will go very far to avoid
|
||||
* resetting context in scenarios like toggling fullscreen, etc.
|
||||
* TODO: Obsolete? Maybe frontend should just always assume this ...
|
||||
*/
|
||||
bool cache_context;
|
||||
|
||||
|
210
libretro_vulkan.h
Normal file
210
libretro_vulkan.h
Normal file
@ -0,0 +1,210 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro API header (libretro_vulkan.h)
|
||||
* ---------------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBRETRO_VULKAN_H__
|
||||
#define LIBRETRO_VULKAN_H__
|
||||
|
||||
#include "libretro.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 1
|
||||
|
||||
struct retro_vulkan_image
|
||||
{
|
||||
VkImageView image_view;
|
||||
VkImageLayout image_layout;
|
||||
VkImageViewCreateInfo create_info;
|
||||
};
|
||||
|
||||
typedef void (*retro_vulkan_set_image_t)(void *handle,
|
||||
const struct retro_vulkan_image *image,
|
||||
uint32_t num_semaphores,
|
||||
const VkSemaphore *semaphores);
|
||||
typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);
|
||||
typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);
|
||||
typedef void (*retro_vulkan_set_command_buffers_t)(void *handle,
|
||||
uint32_t num_cmd,
|
||||
const VkCommandBuffer *cmd);
|
||||
typedef void (*retro_vulkan_wait_sync_index_t)(void *handle);
|
||||
typedef void (*retro_vulkan_lock_queue_t)(void *handle);
|
||||
typedef void (*retro_vulkan_unlock_queue_t)(void *handle);
|
||||
|
||||
/* Note on thread safety:
|
||||
* The Vulkan API is heavily designed around multi-threading, and
|
||||
* the libretro interface for it should also be threading friendly.
|
||||
* A core should be able to build command buffers and submit command buffers to the GPU from
|
||||
* any thread.
|
||||
*/
|
||||
|
||||
struct retro_hw_render_interface_vulkan
|
||||
{
|
||||
/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */
|
||||
enum retro_hw_render_interface_type interface_type;
|
||||
/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */
|
||||
unsigned interface_version;
|
||||
|
||||
/* Opaque handle to the Vulkan backend in the frontend
|
||||
* which must be passed along to all function pointers
|
||||
* in this interface.
|
||||
*
|
||||
* The rationale for including a handle here (which libretro v1 doesn't current do in general) is:
|
||||
*
|
||||
* - Vulkan cores should be able to be freely threaded without lots of fuzz.
|
||||
* This would break frontends which currently rely on TLS
|
||||
* to deal with multiple cores loaded at the same time.
|
||||
* - Fixing this in general is TODO for an eventual libretro v2.
|
||||
*/
|
||||
void *handle;
|
||||
|
||||
/* The Vulkan instance the context is using. */
|
||||
VkInstance instance;
|
||||
/* The physical device used. */
|
||||
VkPhysicalDevice gpu;
|
||||
/* The logical device used. */
|
||||
VkDevice device;
|
||||
|
||||
/* The queue the core must use to submit data.
|
||||
* This queue and index must remain constant throughout the lifetime
|
||||
* of the context.
|
||||
*
|
||||
* This queue will be the queue that supports graphics and compute
|
||||
* if the device supports compute.
|
||||
*/
|
||||
VkQueue queue;
|
||||
unsigned queue_index;
|
||||
|
||||
/* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,
|
||||
* set which image to use for this frame.
|
||||
*
|
||||
* If num_semaphores is non-zero, the frontend will wait for the semaphores provided to be signaled
|
||||
* before using the results further in the pipeline.
|
||||
* Using semaphores is optional for synchronization purposes, but if not using
|
||||
* semaphores, an image memory barrier in vkCmdPipelineBarrier should be used in the graphics_queue.
|
||||
* Example:
|
||||
*
|
||||
* vkCmdPipelineBarrier(cmd,
|
||||
* srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
|
||||
* dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
* image_memory_barrier = {
|
||||
* srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
* dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
* });
|
||||
*
|
||||
* The use of pipeline barriers instead of semaphores is encouraged as it is simpler
|
||||
* and more fine-grained. A layout transition must generally happen anyways which requires a
|
||||
* pipeline barrier.
|
||||
*
|
||||
* The image passed to set_image must have imageUsage flags set to at least
|
||||
* VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.
|
||||
* The core will naturally want to use flags such as
|
||||
* VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or VK_IMAGE_USAGE_TRANSFER_DST_BIT depending
|
||||
* on how the final image is created.
|
||||
*
|
||||
* The image must also have been created with MUTABLE_FORMAT bit set if 8-bit formatt are used, so that the frontend can
|
||||
* reinterpret sRGB formats as it sees fit.
|
||||
*
|
||||
* Images passed to set_image should be created with TILING_OPTIMAL.
|
||||
* The image layout should be transitioned to either VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
|
||||
* The actual image layout used must be set in image_layout.
|
||||
*
|
||||
* The image must be a 2D texture which may or not be layered and/or mipmapped.
|
||||
* The image must be suitable for linear sampling.
|
||||
* While the image_view is typically the only field used,
|
||||
* the frontend may want to reinterpret the texture as sRGB vs. no-sRGB for example
|
||||
* so the VkImageViewCreateInfo used to create the image view must also be passed in.
|
||||
* The data in the pointer to the image struct will not be copied
|
||||
* as the pNext field in create_info cannot be reliably deep-copied.
|
||||
* The image pointer passed to set_image must be valid until retro_video_refresh_t has returned.
|
||||
*
|
||||
* If frame duping is used when passing NULL to retro_video_refresh_t,
|
||||
* the frontend is free to either use the latest image passed to set_image or reuse the older pointer
|
||||
* passed to set_image the frame RETRO_HW_FRAME_BUFFER_VALID was last used.
|
||||
* Essentially, the lifetime of the pointer passed to retro_video_refresh_t should be extended
|
||||
* if frame duping is used so that the frontend can reuse the older pointer.
|
||||
*
|
||||
* If frame duping is used, the frontend will not wait for any semaphores.
|
||||
*/
|
||||
retro_vulkan_set_image_t set_image;
|
||||
|
||||
/* Get the current sync index for this frame which is obtained in frontend by calling
|
||||
* e.g. vkAcquireNextImageKHR before calling retro_run().
|
||||
* This index will correspond to which swapchain buffer is currently the active one.
|
||||
* Knowing this index is very useful for maintaining safe async CPU and GPU operation without stalling.
|
||||
*
|
||||
* The common pattern for synchronization is to receive fences when submitting command buffers
|
||||
* to Vulkan (vkQueueSubmit) and add this fence to a list of fences for frame number get_sync_index().
|
||||
* Next time we receive the same get_sync_index(), we can wait for the fences from before,
|
||||
* which will usually return immediately as the frontend will generally also avoid letting the GPU run ahead too much.
|
||||
* After the fence has signaled, we know that the GPU has completed all GPU work related to work submitted in the frame
|
||||
* we last saw get_sync_index(). This means we can safely reuse or free resources allocated in this frame.
|
||||
*
|
||||
* In theory, even if we wait for the fences correctly, it is not technically safe to write to the image
|
||||
* we earlier passed to the frontend since we're not waiting for the frontend GPU jobs to complete.
|
||||
* The frontend will guarantee that the appropriate pipeline barrier
|
||||
* in graphics_queue has been used such that VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot
|
||||
* start until the frontend is done with the image.
|
||||
*/
|
||||
retro_vulkan_get_sync_index_t get_sync_index;
|
||||
|
||||
/* Returns a bitmask of how many swapchain images we currently have in the frontend.
|
||||
* If bit #N is set in the return value, get_sync_index can return N.
|
||||
* Knowing this value is useful for preallocating per-frame management structures ahead of time.
|
||||
*
|
||||
* While this value will typically remain constant throughout the applications lifecycle,
|
||||
* it may for example change if the frontend suddently changes fullscreen state and/or latency.
|
||||
* If this value ever changes, it is safe to assume that the device is completely idle and all synchronization
|
||||
* objects can be deleted right away as desired.
|
||||
*/
|
||||
retro_vulkan_get_sync_index_mask_t get_sync_index_mask;
|
||||
|
||||
/* Instead of submitting the command buffer to the queue first, the core can pass along
|
||||
* its command buffer to the frontend, and the frontend will submit the command buffer together
|
||||
* with the frontends command buffers. This has the advantage that the overhead of vkQueueSubmit
|
||||
* can be amortized into a single call. For this mode, semaphores in set_image will be ignored, so
|
||||
* vkCmdPipelineBarrier must be used to synchronize the core and frontend.
|
||||
* The command buffers in set_command_buffers are only executed once, even if frame duping is used.
|
||||
* If frame duping is used, set_image should be used for the frames which should be duped instead.
|
||||
*
|
||||
* Command buffers passed to the frontend with set_command_buffers
|
||||
* must not actually be submitted to the GPU until retro_video_refresh_t is called.
|
||||
* The frontend must submit the command buffer before submitting any other command buffers
|
||||
* provided by set_command_buffers. */
|
||||
retro_vulkan_set_command_buffers_t set_command_buffers;
|
||||
|
||||
/* Waits on CPU for device activity for the current sync index to complete.
|
||||
* This is useful since the core will not have a relevant fence to sync with
|
||||
* when the frontend is submitting the command buffers. */
|
||||
retro_vulkan_wait_sync_index_t wait_sync_index;
|
||||
|
||||
/* If the core submits command buffers itself to any of the queues provided in this interface,
|
||||
* the core must lock and unlock the frontend from racing on the VkQueue.
|
||||
* Queue submission can happen on any thread.
|
||||
* Even if queue submission happens on the same thread as retro_run(), the lock/unlock
|
||||
* functions must still be called.
|
||||
*
|
||||
* NOTE: Queue submissions are heavy-weight. */
|
||||
retro_vulkan_lock_queue_t lock_queue;
|
||||
retro_vulkan_unlock_queue_t unlock_queue;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -172,7 +172,7 @@ static void mui_context_reset_textures(mui_handle_t *mui,
|
||||
|
||||
video_texture_image_load(&ti, path);
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, (unsigned*)&mui->textures.list[i].id);
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &mui->textures.list[i].id);
|
||||
|
||||
video_texture_image_free(&ti);
|
||||
}
|
||||
@ -1003,7 +1003,7 @@ static void mui_allocate_white_texture(mui_handle_t *mui)
|
||||
ti.pixels = (uint32_t*)&white_data;
|
||||
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_NEAREST, (unsigned*)&mui->textures.white);
|
||||
TEXTURE_FILTER_NEAREST, &mui->textures.white);
|
||||
}
|
||||
|
||||
static void mui_font(void)
|
||||
@ -1123,8 +1123,8 @@ static void mui_context_bg_destroy(mui_handle_t *mui)
|
||||
if (!mui)
|
||||
return;
|
||||
|
||||
video_driver_texture_unload((uintptr_t*)&mui->textures.bg.id);
|
||||
video_driver_texture_unload((uintptr_t*)&mui->textures.white);
|
||||
video_driver_texture_unload(&mui->textures.bg.id);
|
||||
video_driver_texture_unload(&mui->textures.white);
|
||||
}
|
||||
|
||||
static void mui_context_destroy(void *data)
|
||||
@ -1136,7 +1136,7 @@ static void mui_context_destroy(void *data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < MUI_TEXTURE_LAST; i++)
|
||||
video_driver_texture_unload((uintptr_t*)&mui->textures.list[i].id);
|
||||
video_driver_texture_unload(&mui->textures.list[i].id);
|
||||
|
||||
menu_display_ctl(MENU_DISPLAY_CTL_FONT_MAIN_DEINIT, NULL);
|
||||
|
||||
@ -1155,7 +1155,7 @@ static bool mui_load_image(void *userdata, void *data,
|
||||
case MENU_IMAGE_WALLPAPER:
|
||||
mui_context_bg_destroy(mui);
|
||||
video_driver_texture_load(data,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, (unsigned*)&mui->textures.bg.id);
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &mui->textures.bg.id);
|
||||
mui_allocate_white_texture(mui);
|
||||
break;
|
||||
case MENU_IMAGE_BOXART:
|
||||
|
@ -1053,8 +1053,8 @@ static void xmb_context_destroy_horizontal_list(xmb_handle_t *xmb)
|
||||
if (!path || !strstr(path, ".lpl"))
|
||||
continue;
|
||||
|
||||
video_driver_texture_unload((uintptr_t*)&node->icon);
|
||||
video_driver_texture_unload((uintptr_t*)&node->content_icon);
|
||||
video_driver_texture_unload(&node->icon);
|
||||
video_driver_texture_unload(&node->content_icon);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1168,14 +1168,14 @@ static void xmb_context_reset_horizontal_list(
|
||||
video_texture_image_load(&ti, texturepath);
|
||||
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, (unsigned*)&node->icon);
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &node->icon);
|
||||
|
||||
video_texture_image_free(&ti);
|
||||
|
||||
video_texture_image_load(&ti, content_texturepath);
|
||||
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, (unsigned*)&node->content_icon);
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &node->content_icon);
|
||||
|
||||
video_texture_image_free(&ti);
|
||||
}
|
||||
@ -2167,7 +2167,7 @@ static void xmb_context_bg_destroy(xmb_handle_t *xmb)
|
||||
{
|
||||
if (!xmb)
|
||||
return;
|
||||
video_driver_texture_unload((uintptr_t*)&xmb->textures.bg.id);
|
||||
video_driver_texture_unload(&xmb->textures.bg.id);
|
||||
}
|
||||
|
||||
static bool xmb_load_image(void *userdata, void *data, menu_image_type_t type)
|
||||
@ -2185,7 +2185,7 @@ static bool xmb_load_image(void *userdata, void *data, menu_image_type_t type)
|
||||
xmb_context_bg_destroy(xmb);
|
||||
video_driver_texture_load(data,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR,
|
||||
(unsigned*)&xmb->textures.bg.id);
|
||||
&xmb->textures.bg.id);
|
||||
break;
|
||||
case MENU_IMAGE_BOXART:
|
||||
{
|
||||
@ -2193,7 +2193,7 @@ static bool xmb_load_image(void *userdata, void *data, menu_image_type_t type)
|
||||
xmb->boxart_height = xmb->boxart_width
|
||||
* (float)img->height / (float)img->width;
|
||||
video_driver_texture_load(data,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, (unsigned*)&xmb->boxart);
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR, &xmb->boxart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2333,7 +2333,7 @@ static void xmb_context_reset_textures(
|
||||
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR,
|
||||
(unsigned*)&xmb->textures.list[i].id);
|
||||
&xmb->textures.list[i].id);
|
||||
|
||||
video_texture_image_free(&ti);
|
||||
}
|
||||
@ -2649,7 +2649,7 @@ static void xmb_context_destroy(void *data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < XMB_TEXTURE_LAST; i++)
|
||||
video_driver_texture_unload((uintptr_t*)&xmb->textures.list[i].id);
|
||||
video_driver_texture_unload(&xmb->textures.list[i].id);
|
||||
|
||||
xmb_context_destroy_horizontal_list(xmb);
|
||||
xmb_context_bg_destroy(xmb);
|
||||
|
@ -1145,8 +1145,8 @@ static void zarch_context_bg_destroy(void *data)
|
||||
zui_t *zui = (zui_t*)data;
|
||||
if (!zui)
|
||||
return;
|
||||
video_driver_texture_unload((uintptr_t*)&zui->textures.bg.id);
|
||||
video_driver_texture_unload((uintptr_t*)&zui->textures.white);
|
||||
video_driver_texture_unload(&zui->textures.bg.id);
|
||||
video_driver_texture_unload(&zui->textures.white);
|
||||
}
|
||||
|
||||
static void zarch_context_destroy(void *data)
|
||||
@ -1171,7 +1171,7 @@ static bool zarch_load_image(void *userdata,
|
||||
zarch_context_bg_destroy(zui);
|
||||
video_driver_texture_load(data,
|
||||
TEXTURE_FILTER_MIPMAP_LINEAR,
|
||||
(unsigned*)&zui->textures.bg.id);
|
||||
&zui->textures.bg.id);
|
||||
break;
|
||||
case MENU_IMAGE_BOXART:
|
||||
break;
|
||||
@ -1191,7 +1191,7 @@ static void zarch_allocate_white_texture(zui_t *zui)
|
||||
|
||||
video_driver_texture_load(&ti,
|
||||
TEXTURE_FILTER_NEAREST,
|
||||
(unsigned*)&zui->textures.white);
|
||||
&zui->textures.white);
|
||||
}
|
||||
|
||||
static void zarch_context_reset(void *data)
|
||||
|
236
menu/drivers_display/menu_display_vulkan.c
Normal file
236
menu/drivers_display/menu_display_vulkan.c
Normal file
@ -0,0 +1,236 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2016 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2015 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include "../../config.def.h"
|
||||
#include "../../gfx/font_driver.h"
|
||||
#include "../../gfx/video_context_driver.h"
|
||||
#include "../../gfx/common/vulkan_common.h"
|
||||
|
||||
#include "../menu_display.h"
|
||||
|
||||
static const float vk_vertexes[] = {
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 0,
|
||||
1, 1
|
||||
};
|
||||
|
||||
static const float vk_tex_coords[] = {
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 0,
|
||||
1, 1
|
||||
};
|
||||
|
||||
static vk_t *vk_get_ptr(void)
|
||||
{
|
||||
vk_t *vk = (vk_t*)video_driver_get_ptr(false);
|
||||
if (!vk)
|
||||
return NULL;
|
||||
return vk;
|
||||
}
|
||||
|
||||
static void *menu_display_vk_get_default_mvp(void)
|
||||
{
|
||||
vk_t *vk = vk_get_ptr();
|
||||
if (!vk)
|
||||
return NULL;
|
||||
return &vk->mvp_no_rot;
|
||||
}
|
||||
|
||||
static unsigned to_display_pipeline(enum menu_display_prim_type prim_type, bool blend)
|
||||
{
|
||||
return ((prim_type == MENU_DISPLAY_PRIM_TRIANGLESTRIP) << 1) | (blend << 0);
|
||||
}
|
||||
|
||||
static void menu_display_vk_draw(void *data)
|
||||
/*
|
||||
float x, float y,
|
||||
unsigned width, unsigned height,
|
||||
struct gfx_coords *coords,
|
||||
void *matrix_data,
|
||||
uintptr_t handle,
|
||||
enum menu_display_prim_type prim_type) */
|
||||
{
|
||||
menu_display_ctx_draw_t *draw = (menu_display_ctx_draw_t*)data;
|
||||
struct vk_texture *texture;
|
||||
const float *vertex, *tex_coord, *color;
|
||||
math_matrix_4x4 *mat;
|
||||
struct vk_buffer_range range;
|
||||
struct vk_vertex *pv;
|
||||
unsigned i;
|
||||
|
||||
vk_t *vk = vk_get_ptr();
|
||||
if (!vk)
|
||||
return;
|
||||
|
||||
texture = (struct vk_texture*)draw->texture;
|
||||
mat = (math_matrix_4x4*)draw->matrix_data;
|
||||
vertex = draw->coords->vertex;
|
||||
tex_coord = draw->coords->tex_coord;
|
||||
color = draw->coords->color;
|
||||
|
||||
/* TODO - edge case */
|
||||
if (draw->height <= 0)
|
||||
draw->height = 1;
|
||||
|
||||
if (!mat)
|
||||
mat = (math_matrix_4x4*)menu_display_vk_get_default_mvp();
|
||||
if (!vertex)
|
||||
vertex = &vk_vertexes[0];
|
||||
if (!tex_coord)
|
||||
tex_coord = &vk_tex_coords[0];
|
||||
if (!texture)
|
||||
texture = &vk->display.blank_texture;
|
||||
|
||||
vk->vk_vp.x = draw->x;
|
||||
vk->vk_vp.y = vk->context->swapchain_height - draw->y - draw->height;
|
||||
vk->vk_vp.width = draw->width;
|
||||
vk->vk_vp.height = draw->height;
|
||||
vk->vk_vp.minDepth = 0.0f;
|
||||
vk->vk_vp.maxDepth = 1.0f;
|
||||
vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT;
|
||||
|
||||
/* Bake interleaved VBO. Kinda ugly, we should probably try to move to
|
||||
* an interleaved model to begin with ... */
|
||||
if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->vbo,
|
||||
draw->coords->vertices * sizeof(struct vk_vertex), &range))
|
||||
return;
|
||||
|
||||
pv = (struct vk_vertex*)range.data;
|
||||
for (i = 0; i < draw->coords->vertices; i++, pv++)
|
||||
{
|
||||
pv->x = *vertex++;
|
||||
pv->y = *vertex++;
|
||||
pv->tex_x = *tex_coord++;
|
||||
pv->tex_y = *tex_coord++;
|
||||
pv->color.r = *color++;
|
||||
pv->color.g = *color++;
|
||||
pv->color.b = *color++;
|
||||
pv->color.a = *color++;
|
||||
}
|
||||
|
||||
{
|
||||
const struct vk_draw_triangles call = {
|
||||
vk->display.pipelines[to_display_pipeline(draw->prim_type, vk->display.blend)],
|
||||
texture,
|
||||
texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest,
|
||||
mat,
|
||||
&range,
|
||||
draw->coords->vertices,
|
||||
};
|
||||
vulkan_draw_triangles(vk, &call);
|
||||
}
|
||||
}
|
||||
|
||||
static void menu_display_vk_draw_bg(void *data)
|
||||
{
|
||||
struct gfx_coords coords;
|
||||
const float *new_vertex = NULL;
|
||||
const float *new_tex_coord = NULL;
|
||||
menu_display_ctx_draw_t *draw = (menu_display_ctx_draw_t*)data;
|
||||
global_t *global = global_get_ptr();
|
||||
settings_t *settings = config_get_ptr();
|
||||
vk_t *vk = vk_get_ptr();
|
||||
|
||||
if (!vk || !draw)
|
||||
return;
|
||||
|
||||
if (!new_vertex)
|
||||
new_vertex = &vk_vertexes[0];
|
||||
if (!new_tex_coord)
|
||||
new_tex_coord = &vk_tex_coords[0];
|
||||
|
||||
coords.vertices = draw->vertex_count;
|
||||
coords.vertex = new_vertex;
|
||||
coords.tex_coord = new_tex_coord;
|
||||
coords.color = (const float*)draw->color;
|
||||
|
||||
vk->display.blend = true;
|
||||
|
||||
menu_display_ctl(MENU_DISPLAY_CTL_SET_VIEWPORT, NULL);
|
||||
|
||||
if (
|
||||
(settings->menu.pause_libretro
|
||||
|| !rarch_ctl(RARCH_CTL_IS_INITED, NULL)
|
||||
|| rarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)
|
||||
)
|
||||
&& !draw->force_transparency && draw->texture)
|
||||
coords.color = (const float*)draw->color2;
|
||||
|
||||
draw->x = 0;
|
||||
draw->y = 0;
|
||||
draw->coords = &coords;
|
||||
draw->matrix_data = (math_matrix_4x4*)
|
||||
menu_display_vk_get_default_mvp();
|
||||
|
||||
menu_display_vk_draw(draw);
|
||||
|
||||
vk->display.blend = false;
|
||||
}
|
||||
|
||||
static void menu_display_vk_restore_clear_color(void)
|
||||
{
|
||||
//glClearColor(0.0f, 0.0f, 0.0f, 0.00f);
|
||||
}
|
||||
|
||||
static void menu_display_vk_clear_color(void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* FIXME: This makes little sense in Vulkan.
|
||||
* We shouldn't be clearing mid-screen nilly willy. */
|
||||
}
|
||||
|
||||
static const float *menu_display_vk_get_tex_coords(void)
|
||||
{
|
||||
return &vk_tex_coords[0];
|
||||
}
|
||||
|
||||
static void menu_display_vk_blend_begin(void)
|
||||
{
|
||||
vk_t *vk = vk_get_ptr();
|
||||
vk->display.blend = true;
|
||||
}
|
||||
|
||||
static void menu_display_vk_blend_end(void)
|
||||
{
|
||||
vk_t *vk = vk_get_ptr();
|
||||
vk->display.blend = false;
|
||||
}
|
||||
|
||||
static bool menu_display_vk_font_init_first(
|
||||
void **font_handle, void *video_data, const char *font_path,
|
||||
float font_size)
|
||||
{
|
||||
return font_driver_init_first(NULL, font_handle, video_data,
|
||||
font_path, font_size, true, FONT_DRIVER_RENDER_VULKAN_API);
|
||||
}
|
||||
|
||||
menu_display_ctx_driver_t menu_display_ctx_vulkan = {
|
||||
menu_display_vk_draw,
|
||||
menu_display_vk_draw_bg,
|
||||
menu_display_vk_blend_begin,
|
||||
menu_display_vk_blend_end,
|
||||
menu_display_vk_restore_clear_color,
|
||||
menu_display_vk_clear_color,
|
||||
menu_display_vk_get_default_mvp,
|
||||
menu_display_vk_get_tex_coords,
|
||||
menu_display_vk_font_init_first,
|
||||
MENU_VIDEO_DRIVER_VULKAN,
|
||||
"menu_display_vulkan",
|
||||
};
|
@ -42,6 +42,9 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = {
|
||||
#endif
|
||||
#ifdef HAVE_OPENGL
|
||||
&menu_display_ctx_gl,
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
&menu_display_ctx_vulkan,
|
||||
#endif
|
||||
&menu_display_ctx_null,
|
||||
NULL,
|
||||
@ -72,6 +75,10 @@ static bool menu_display_check_compatibility(
|
||||
if (string_is_equal(video_driver, "gl"))
|
||||
return true;
|
||||
break;
|
||||
case MENU_VIDEO_DRIVER_VULKAN:
|
||||
if (!strcmp(video_driver, "vulkan"))
|
||||
return true;
|
||||
break;
|
||||
case MENU_VIDEO_DRIVER_DIRECT3D:
|
||||
if (string_is_equal(video_driver, "d3d"))
|
||||
return true;
|
||||
|
@ -93,6 +93,7 @@ enum menu_display_driver_type
|
||||
{
|
||||
MENU_VIDEO_DRIVER_GENERIC = 0,
|
||||
MENU_VIDEO_DRIVER_OPENGL,
|
||||
MENU_VIDEO_DRIVER_VULKAN,
|
||||
MENU_VIDEO_DRIVER_DIRECT3D
|
||||
};
|
||||
|
||||
@ -175,6 +176,7 @@ void menu_display_handle_wallpaper_upload(void *task_data,
|
||||
void *user_data, const char *err);
|
||||
|
||||
extern menu_display_ctx_driver_t menu_display_ctx_gl;
|
||||
extern menu_display_ctx_driver_t menu_display_ctx_vulkan;
|
||||
extern menu_display_ctx_driver_t menu_display_ctx_d3d;
|
||||
extern menu_display_ctx_driver_t menu_display_ctx_null;
|
||||
|
||||
|
@ -3337,11 +3337,11 @@ int menu_displaylist_push_list(menu_displaylist_info_t *info, unsigned type)
|
||||
break;
|
||||
case DISPLAYLIST_SHADER_PRESET:
|
||||
info->type_default = MENU_FILE_SHADER_PRESET;
|
||||
strlcpy(info->exts, "cgp|glslp", sizeof(info->exts));
|
||||
strlcpy(info->exts, "cgp|glslp|slangp", sizeof(info->exts));
|
||||
break;
|
||||
case DISPLAYLIST_SHADER_PASS:
|
||||
info->type_default = MENU_FILE_SHADER;
|
||||
strlcpy(info->exts, "cg|glsl", sizeof(info->exts));
|
||||
strlcpy(info->exts, "cg|glsl|slang", sizeof(info->exts));
|
||||
break;
|
||||
case DISPLAYLIST_VIDEO_FILTERS:
|
||||
info->type_default = MENU_FILE_VIDEOFILTER;
|
||||
|
@ -299,6 +299,7 @@ typedef struct
|
||||
/* Menu shader */
|
||||
char default_glslp[PATH_MAX_LENGTH];
|
||||
char default_cgp[PATH_MAX_LENGTH];
|
||||
char default_slangp[PATH_MAX_LENGTH];
|
||||
|
||||
char db_playlist_file[PATH_MAX_LENGTH];
|
||||
} menu_handle_t;
|
||||
|
@ -645,6 +645,9 @@ extern "C" {
|
||||
#define MENU_VALUE_CGP 0x0b8865bfU
|
||||
#define MENU_VALUE_GLSL 0x7c976537U
|
||||
#define MENU_VALUE_CG 0x0059776fU
|
||||
#define MENU_VALUE_SLANG 0x105ce63aU
|
||||
#define MENU_VALUE_SLANGP 0x1bf9adeaU
|
||||
|
||||
#define MENU_VALUE_RETROPAD 0x9e6703e6U
|
||||
#define MENU_VALUE_RETROKEYBOARD 0x9d8b6ea2U
|
||||
|
||||
|
@ -63,10 +63,16 @@ void menu_shader_manager_init(menu_handle_t *menu)
|
||||
sizeof(menu->default_glslp));
|
||||
path_remove_extension(menu->default_glslp);
|
||||
strlcat(menu->default_glslp, ".glslp", sizeof(menu->default_glslp));
|
||||
|
||||
fill_pathname_base(menu->default_cgp, config_path,
|
||||
sizeof(menu->default_cgp));
|
||||
path_remove_extension(menu->default_cgp);
|
||||
strlcat(menu->default_cgp, ".cgp", sizeof(menu->default_cgp));
|
||||
|
||||
fill_pathname_base(menu->default_slangp, config_path,
|
||||
sizeof(menu->default_slangp));
|
||||
path_remove_extension(menu->default_slangp);
|
||||
strlcat(menu->default_slangp, ".slangp", sizeof(menu->default_slangp));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -74,6 +80,8 @@ void menu_shader_manager_init(menu_handle_t *menu)
|
||||
sizeof(menu->default_glslp));
|
||||
strlcpy(menu->default_cgp, "menu.cgp",
|
||||
sizeof(menu->default_cgp));
|
||||
strlcpy(menu->default_slangp, "menu.slangp",
|
||||
sizeof(menu->default_slangp));
|
||||
}
|
||||
|
||||
ext = path_get_extension(settings->video.shader_path);
|
||||
@ -83,6 +91,7 @@ void menu_shader_manager_init(menu_handle_t *menu)
|
||||
{
|
||||
case MENU_VALUE_GLSLP:
|
||||
case MENU_VALUE_CGP:
|
||||
case MENU_VALUE_SLANGP:
|
||||
conf = config_file_new(settings->video.shader_path);
|
||||
if (conf)
|
||||
{
|
||||
@ -97,6 +106,7 @@ void menu_shader_manager_init(menu_handle_t *menu)
|
||||
break;
|
||||
case MENU_VALUE_GLSL:
|
||||
case MENU_VALUE_CG:
|
||||
case MENU_VALUE_SLANG:
|
||||
strlcpy(shader->pass[0].source.path, settings->video.shader_path,
|
||||
sizeof(shader->pass[0].source.path));
|
||||
shader->passes = 1;
|
||||
@ -118,6 +128,12 @@ void menu_shader_manager_init(menu_handle_t *menu)
|
||||
conf = config_file_new(preset_path);
|
||||
}
|
||||
|
||||
if (!conf)
|
||||
{
|
||||
fill_pathname_join(preset_path, shader_dir, "menu.slangp", sizeof(preset_path));
|
||||
conf = config_file_new(preset_path);
|
||||
}
|
||||
|
||||
if (conf)
|
||||
{
|
||||
if (video_shader_read_conf_cgp(conf, shader))
|
||||
@ -235,13 +251,17 @@ void menu_shader_manager_save_preset(
|
||||
|
||||
/* Append extension automatically as appropriate. */
|
||||
if ( !strstr(basename, ".cgp")
|
||||
&& !strstr(basename, ".glslp"))
|
||||
&& !strstr(basename, ".glslp")
|
||||
&& !strstr(basename, ".slangp"))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RARCH_SHADER_GLSL:
|
||||
strlcat(buffer, ".glslp", sizeof(buffer));
|
||||
break;
|
||||
case RARCH_SHADER_SLANG:
|
||||
strlcat(buffer, ".slangp", sizeof(buffer));
|
||||
break;
|
||||
case RARCH_SHADER_CG:
|
||||
strlcat(buffer, ".cgp", sizeof(buffer));
|
||||
break;
|
||||
@ -250,8 +270,22 @@ void menu_shader_manager_save_preset(
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *conf_path = (type == RARCH_SHADER_GLSL) ?
|
||||
menu->default_glslp : menu->default_cgp;
|
||||
const char *conf_path = NULL;
|
||||
switch (type)
|
||||
{
|
||||
case RARCH_SHADER_GLSL:
|
||||
conf_path = menu->default_glslp;
|
||||
break;
|
||||
|
||||
case RARCH_SHADER_SLANG:
|
||||
conf_path = menu->default_slangp;
|
||||
break;
|
||||
|
||||
default:
|
||||
case RARCH_SHADER_CG:
|
||||
conf_path = menu->default_cgp;
|
||||
break;
|
||||
}
|
||||
strlcpy(buffer, conf_path, sizeof(buffer));
|
||||
}
|
||||
|
||||
@ -323,6 +357,7 @@ unsigned menu_shader_manager_get_type(const struct video_shader *shader)
|
||||
{
|
||||
case RARCH_SHADER_CG:
|
||||
case RARCH_SHADER_GLSL:
|
||||
case RARCH_SHADER_SLANG:
|
||||
if (type == RARCH_SHADER_NONE)
|
||||
type = pass_type;
|
||||
else if (type != pass_type)
|
||||
@ -373,6 +408,8 @@ void menu_shader_manager_apply_changes(void)
|
||||
shader_type = RARCH_SHADER_GLSL;
|
||||
#elif defined(HAVE_CG) || defined(HAVE_HLSL)
|
||||
shader_type = RARCH_SHADER_CG;
|
||||
#elif defined(HAVE_VULKAN)
|
||||
shader_type = RARCH_SHADER_SLANG;
|
||||
#endif
|
||||
}
|
||||
menu_shader_manager_set_preset(NULL, shader_type, NULL);
|
||||
|
@ -389,6 +389,7 @@ if [ "$OS" != 'Win32' ]; then
|
||||
fi
|
||||
check_lib STRCASESTR "$CLIB" strcasestr
|
||||
check_lib MMAP "$CLIB" mmap
|
||||
check_lib VULKAN -lvulkan vkCreateInstance
|
||||
|
||||
check_pkgconf PYTHON python3
|
||||
|
||||
|
@ -70,3 +70,4 @@ HAVE_MMAP=auto # MMAP support
|
||||
HAVE_QT=no # QT companion support
|
||||
HAVE_XSHM=no # XShm video driver support (disabled because it's just a dummied out stub)
|
||||
HAVE_CHEEVOS=yes # Disable Retro Achievements
|
||||
HAVE_VULKAN=auto # Enable Vulkan support
|
||||
|
@ -627,6 +627,7 @@ static bool ffmpeg_init_muxer_post(ffmpeg_t *handle)
|
||||
handle->video.encoder);
|
||||
|
||||
stream->codec = handle->video.codec;
|
||||
stream->time_base = stream->codec->time_base;
|
||||
handle->muxer.vstream = stream;
|
||||
handle->muxer.vstream->sample_aspect_ratio =
|
||||
handle->video.codec->sample_aspect_ratio;
|
||||
@ -636,6 +637,7 @@ static bool ffmpeg_init_muxer_post(ffmpeg_t *handle)
|
||||
stream = avformat_new_stream(handle->muxer.ctx,
|
||||
handle->audio.encoder);
|
||||
stream->codec = handle->audio.codec;
|
||||
stream->time_base = stream->codec->time_base;
|
||||
handle->muxer.astream = stream;
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,8 @@
|
||||
#define SHADER_EXT_GLSLP 0x0f840c87U
|
||||
#define SHADER_EXT_CG 0x0059776fU
|
||||
#define SHADER_EXT_CGP 0x0b8865bfU
|
||||
#define SHADER_EXT_SLANG 0x105ce63aU
|
||||
#define SHADER_EXT_SLANGP 0x1bf9adeaU
|
||||
|
||||
#define runloop_cmd_triggered(cmd, id) BIT64_GET(cmd->state[2], id)
|
||||
|
||||
@ -351,6 +353,10 @@ static void check_shader_dir(rarch_dir_list_t *dir_list,
|
||||
case SHADER_EXT_GLSLP:
|
||||
type = RARCH_SHADER_GLSL;
|
||||
break;
|
||||
case SHADER_EXT_SLANG:
|
||||
case SHADER_EXT_SLANGP:
|
||||
type = RARCH_SHADER_SLANG;
|
||||
break;
|
||||
case SHADER_EXT_CG:
|
||||
case SHADER_EXT_CGP:
|
||||
type = RARCH_SHADER_CG;
|
||||
|
Loading…
Reference in New Issue
Block a user