diff --git a/.gitignore b/.gitignore index cd80974377..d93773a455 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,9 @@ menu/driverspzarch.c /media/shaders_glsl/ /obj-w32/ +# Ctags +/tags + # Android /pkg/android/phoenix/obj/ /pkg/android/phoenix/assets/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..9a7de532c9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/glslang/glslang"] + path = deps/glslang/glslang + url = git://github.com/KhronosGroup/glslang.git diff --git a/Makefile b/Makefile index 85cd55a8c1..bcf331d68c 100644 --- a/Makefile +++ b/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 $@ $< diff --git a/Makefile.common b/Makefile.common index 856fccda13..6604e1a868 100644 --- a/Makefile.common +++ b/Makefile.common @@ -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 diff --git a/command.c b/command.c index 9911a756ba..21d4bad62a 100644 --- a/command.c +++ b/command.c @@ -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; } diff --git a/config.def.h b/config.def.h index ab489b6631..8195c17f48 100644 --- a/config.def.h +++ b/config.def.h @@ -29,6 +29,7 @@ enum { VIDEO_GL = 0, + VIDEO_VULKAN, VIDEO_XVIDEO, VIDEO_SDL, VIDEO_SDL2, diff --git a/cores/libretro-test-vulkan/Makefile b/cores/libretro-test-vulkan/Makefile new file mode 100644 index 0000000000..28b4c9386d --- /dev/null +++ b/cores/libretro-test-vulkan/Makefile @@ -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 + diff --git a/cores/libretro-test-vulkan/libretro-test.c b/cores/libretro-test-vulkan/libretro-test.c new file mode 100644 index 0000000000..1db7e5b7d1 --- /dev/null +++ b/cores/libretro-test-vulkan/libretro-test.c @@ -0,0 +1,793 @@ +#include +#include +#include +#include +#include + +#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; +} + diff --git a/cores/libretro-test-vulkan/link.T b/cores/libretro-test-vulkan/link.T new file mode 100644 index 0000000000..b0c262db9e --- /dev/null +++ b/cores/libretro-test-vulkan/link.T @@ -0,0 +1,5 @@ +{ + global: retro_*; + local: *; +}; + diff --git a/cores/libretro-test-vulkan/shaders/Makefile b/cores/libretro-test-vulkan/shaders/Makefile new file mode 100644 index 0000000000..e33ac65d2a --- /dev/null +++ b/cores/libretro-test-vulkan/shaders/Makefile @@ -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 diff --git a/cores/libretro-test-vulkan/shaders/triangle.frag b/cores/libretro-test-vulkan/shaders/triangle.frag new file mode 100644 index 0000000000..6d12ebf3a0 --- /dev/null +++ b/cores/libretro-test-vulkan/shaders/triangle.frag @@ -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; +} diff --git a/cores/libretro-test-vulkan/shaders/triangle.frag.inc b/cores/libretro-test-vulkan/shaders/triangle.frag.inc new file mode 100644 index 0000000000..a0481135ac --- /dev/null +++ b/cores/libretro-test-vulkan/shaders/triangle.frag.inc @@ -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; diff --git a/cores/libretro-test-vulkan/shaders/triangle.vert b/cores/libretro-test-vulkan/shaders/triangle.vert new file mode 100644 index 0000000000..48bb222fc9 --- /dev/null +++ b/cores/libretro-test-vulkan/shaders/triangle.vert @@ -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; +} diff --git a/cores/libretro-test-vulkan/shaders/triangle.vert.inc b/cores/libretro-test-vulkan/shaders/triangle.vert.inc new file mode 100644 index 0000000000..f2ab078b2a --- /dev/null +++ b/cores/libretro-test-vulkan/shaders/triangle.vert.inc @@ -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; diff --git a/cores/libretro-test/Makefile b/cores/libretro-test/Makefile index c73a71d7ff..847a8617d9 100644 --- a/cores/libretro-test/Makefile +++ b/cores/libretro-test/Makefile @@ -120,6 +120,8 @@ else CFLAGS += -std=gnu99 endif +CFLAGS += -I../../libretro-common/include + all: $(TARGET) $(TARGET): $(OBJECTS) diff --git a/cores/libretro-test/libretro-test.c b/cores/libretro-test/libretro-test.c index 7d519d825f..bc7e592399 100644 --- a/cores/libretro-test/libretro-test.c +++ b/cores/libretro-test/libretro-test.c @@ -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; } diff --git a/deps/glslang/glslang b/deps/glslang/glslang new file mode 160000 index 0000000000..9d565d9ef8 --- /dev/null +++ b/deps/glslang/glslang @@ -0,0 +1 @@ +Subproject commit 9d565d9ef802c6984122d182bc1fc477dd5e07ba diff --git a/deps/glslang/glslang.cpp b/deps/glslang/glslang.cpp new file mode 100644 index 0000000000..7b25f53e70 --- /dev/null +++ b/deps/glslang/glslang.cpp @@ -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 . + */ + +#include "glslang.hpp" + +#include "ShaderLang.h" +#include "GlslangToSpv.h" +#include +#include +#include +#include + +#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 *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; +} + diff --git a/deps/glslang/glslang.hpp b/deps/glslang/glslang.hpp new file mode 100644 index 0000000000..4cc8bab812 --- /dev/null +++ b/deps/glslang/glslang.hpp @@ -0,0 +1,24 @@ +#ifndef GLSLANG_COMPILER_HPP +#define GLSLANG_COMPILER_HPP + +#include +#include +#include + +namespace glslang +{ + enum Stage + { + StageVertex = 0, + StageTessControl, + StageTessEvaluation, + StageGeometry, + StageFragment, + StageCompute + }; + + bool compile_spirv(const std::string &source, Stage stage, std::vector *spirv); +} + +#endif + diff --git a/deps/glslang/glslang_tab.cpp b/deps/glslang/glslang_tab.cpp new file mode 100644 index 0000000000..260f356d89 --- /dev/null +++ b/deps/glslang/glslang_tab.cpp @@ -0,0 +1,6805 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation 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 . */ + +/* 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. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +#line 41 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:339 */ + + +/* Based on: +ANSI C Yacc grammar + +In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a +matching Lex specification) for the April 30, 1985 draft version of the +ANSI C standard. Tom Stockfisch reposted it to net.sources in 1987; that +original, as mentioned in the answer to question 17.25 of the comp.lang.c +FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar as +possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +#include "SymbolTable.h" +#include "ParseHelper.h" +#include "../Public/ShaderLang.h" + +using namespace glslang; + + +#line 91 "glslang_tab.cpp" /* yacc.c:339 */ + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "glslang_tab.cpp.h". */ +#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:355 */ + + 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 382 "glslang_tab.cpp" /* yacc.c:355 */ +}; + +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 */ + +/* Copy the second part of user declarations. */ +#line 98 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:358 */ + + +/* windows only pragma */ +#ifdef _MSC_VER + #pragma warning(disable : 4065) + #pragma warning(disable : 4127) + #pragma warning(disable : 4244) +#endif + +#define parseContext (*pParseContext) +#define yyerror(context, msg) context->parserError(msg) + +extern int yylex(YYSTYPE*, TParseContext&); + + +#line 413 "glslang_tab.cpp" /* yacc.c:358 */ + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 199 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 4716 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 219 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 100 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 370 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 502 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 473 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 226, 226, 232, 235, 238, 242, 245, 249, 252, + 260, 263, 266, 269, 272, 277, 285, 292, 299, 305, + 309, 316, 319, 325, 332, 342, 350, 355, 385, 391, + 395, 399, 419, 420, 421, 422, 428, 429, 434, 439, + 448, 449, 454, 462, 463, 469, 478, 479, 484, 489, + 494, 502, 503, 510, 520, 521, 530, 531, 540, 541, + 550, 551, 559, 560, 568, 569, 577, 578, 578, 596, + 597, 611, 615, 619, 623, 628, 632, 636, 640, 644, + 648, 652, 659, 662, 672, 679, 684, 689, 697, 701, + 705, 709, 714, 719, 728, 728, 739, 743, 750, 757, + 760, 767, 775, 795, 813, 828, 851, 862, 872, 882, + 892, 901, 904, 908, 912, 917, 925, 930, 935, 940, + 945, 954, 965, 992, 1001, 1008, 1015, 1025, 1031, 1034, + 1041, 1045, 1049, 1057, 1063, 1066, 1077, 1080, 1083, 1086, + 1090, 1094, 1101, 1105, 1117, 1131, 1136, 1142, 1148, 1155, + 1161, 1166, 1171, 1176, 1183, 1187, 1191, 1195, 1199, 1203, + 1208, 1219, 1222, 1227, 1231, 1240, 1245, 1253, 1257, 1267, + 1271, 1275, 1280, 1284, 1289, 1293, 1298, 1303, 1308, 1314, + 1320, 1326, 1331, 1336, 1341, 1346, 1351, 1356, 1362, 1368, + 1374, 1379, 1384, 1389, 1394, 1399, 1404, 1409, 1414, 1419, + 1424, 1429, 1434, 1440, 1446, 1452, 1458, 1464, 1470, 1476, + 1482, 1488, 1494, 1500, 1506, 1510, 1515, 1520, 1525, 1530, + 1535, 1540, 1545, 1550, 1555, 1560, 1565, 1570, 1575, 1580, + 1585, 1590, 1595, 1600, 1605, 1610, 1615, 1620, 1625, 1630, + 1635, 1640, 1645, 1650, 1655, 1660, 1665, 1670, 1675, 1680, + 1685, 1690, 1695, 1700, 1705, 1710, 1715, 1720, 1725, 1730, + 1735, 1740, 1745, 1750, 1755, 1760, 1765, 1770, 1775, 1780, + 1785, 1790, 1795, 1800, 1805, 1810, 1815, 1820, 1825, 1830, + 1835, 1840, 1845, 1850, 1855, 1860, 1865, 1870, 1875, 1881, + 1886, 1902, 1908, 1914, 1923, 1923, 1934, 1934, 1944, 1947, + 1960, 1978, 2002, 2006, 2012, 2017, 2028, 2031, 2037, 2046, + 2049, 2055, 2059, 2060, 2066, 2067, 2068, 2069, 2070, 2071, + 2072, 2076, 2077, 2081, 2077, 2093, 2094, 2098, 2098, 2105, + 2105, 2119, 2122, 2130, 2138, 2149, 2150, 2154, 2161, 2165, + 2173, 2177, 2190, 2190, 2210, 2213, 2219, 2231, 2243, 2243, + 2258, 2258, 2274, 2274, 2295, 2298, 2304, 2307, 2313, 2317, + 2324, 2329, 2334, 2341, 2359, 2368, 2372, 2379, 2382, 2388, + 2388 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "ATTRIBUTE", "VARYING", "CONST", "BOOL", + "FLOAT", "DOUBLE", "INT", "UINT", "BREAK", "CONTINUE", "DO", "ELSE", + "FOR", "IF", "DISCARD", "RETURN", "SWITCH", "CASE", "DEFAULT", + "SUBROUTINE", "BVEC2", "BVEC3", "BVEC4", "IVEC2", "IVEC3", "IVEC4", + "UVEC2", "UVEC3", "UVEC4", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", + "MAT4", "CENTROID", "IN", "OUT", "INOUT", "UNIFORM", "PATCH", "SAMPLE", + "BUFFER", "SHARED", "COHERENT", "VOLATILE", "RESTRICT", "READONLY", + "WRITEONLY", "DVEC2", "DVEC3", "DVEC4", "DMAT2", "DMAT3", "DMAT4", + "NOPERSPECTIVE", "FLAT", "SMOOTH", "LAYOUT", "MAT2X2", "MAT2X3", + "MAT2X4", "MAT3X2", "MAT3X3", "MAT3X4", "MAT4X2", "MAT4X3", "MAT4X4", + "DMAT2X2", "DMAT2X3", "DMAT2X4", "DMAT3X2", "DMAT3X3", "DMAT3X4", + "DMAT4X2", "DMAT4X3", "DMAT4X4", "ATOMIC_UINT", "SAMPLER1D", "SAMPLER2D", + "SAMPLER3D", "SAMPLERCUBE", "SAMPLER1DSHADOW", "SAMPLER2DSHADOW", + "SAMPLERCUBESHADOW", "SAMPLER1DARRAY", "SAMPLER2DARRAY", + "SAMPLER1DARRAYSHADOW", "SAMPLER2DARRAYSHADOW", "ISAMPLER1D", + "ISAMPLER2D", "ISAMPLER3D", "ISAMPLERCUBE", "ISAMPLER1DARRAY", + "ISAMPLER2DARRAY", "USAMPLER1D", "USAMPLER2D", "USAMPLER3D", + "USAMPLERCUBE", "USAMPLER1DARRAY", "USAMPLER2DARRAY", "SAMPLER2DRECT", + "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT", "USAMPLER2DRECT", + "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER", "SAMPLERCUBEARRAY", + "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", "USAMPLERCUBEARRAY", + "SAMPLER2DMS", "ISAMPLER2DMS", "USAMPLER2DMS", "SAMPLER2DMSARRAY", + "ISAMPLER2DMSARRAY", "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", + "IMAGE1D", "IIMAGE1D", "UIMAGE1D", "IMAGE2D", "IIMAGE2D", "UIMAGE2D", + "IMAGE3D", "IIMAGE3D", "UIMAGE3D", "IMAGE2DRECT", "IIMAGE2DRECT", + "UIMAGE2DRECT", "IMAGECUBE", "IIMAGECUBE", "UIMAGECUBE", "IMAGEBUFFER", + "IIMAGEBUFFER", "UIMAGEBUFFER", "IMAGE1DARRAY", "IIMAGE1DARRAY", + "UIMAGE1DARRAY", "IMAGE2DARRAY", "IIMAGE2DARRAY", "UIMAGE2DARRAY", + "IMAGECUBEARRAY", "IIMAGECUBEARRAY", "UIMAGECUBEARRAY", "IMAGE2DMS", + "IIMAGE2DMS", "UIMAGE2DMS", "IMAGE2DMSARRAY", "IIMAGE2DMSARRAY", + "UIMAGE2DMSARRAY", "STRUCT", "VOID", "WHILE", "IDENTIFIER", "TYPE_NAME", + "FLOATCONSTANT", "DOUBLECONSTANT", "INTCONSTANT", "UINTCONSTANT", + "BOOLCONSTANT", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", + "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", + "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", + "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "LEFT_PAREN", + "RIGHT_PAREN", "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", + "RIGHT_BRACE", "DOT", "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", + "DASH", "TILDE", "PLUS", "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", + "RIGHT_ANGLE", "VERTICAL_BAR", "CARET", "AMPERSAND", "QUESTION", + "INVARIANT", "PRECISE", "HIGH_PRECISION", "MEDIUM_PRECISION", + "LOW_PRECISION", "PRECISION", "PACKED", "RESOURCE", "SUPERP", "$accept", + "variable_identifier", "primary_expression", "postfix_expression", + "integer_expression", "function_call", "function_call_or_method", + "function_call_generic", "function_call_header_no_parameters", + "function_call_header_with_parameters", "function_call_header", + "function_identifier", "unary_expression", "unary_operator", + "multiplicative_expression", "additive_expression", "shift_expression", + "relational_expression", "equality_expression", "and_expression", + "exclusive_or_expression", "inclusive_or_expression", + "logical_and_expression", "logical_xor_expression", + "logical_or_expression", "conditional_expression", "$@1", + "assignment_expression", "assignment_operator", "expression", + "constant_expression", "declaration", "block_structure", "$@2", + "identifier_list", "function_prototype", "function_declarator", + "function_header_with_parameters", "function_header", + "parameter_declarator", "parameter_declaration", + "parameter_type_specifier", "init_declarator_list", "single_declaration", + "fully_specified_type", "invariant_qualifier", "interpolation_qualifier", + "layout_qualifier", "layout_qualifier_id_list", "layout_qualifier_id", + "precise_qualifier", "type_qualifier", "single_type_qualifier", + "storage_qualifier", "type_name_list", "type_specifier", + "array_specifier", "type_specifier_nonarray", "precision_qualifier", + "struct_specifier", "$@3", "$@4", "struct_declaration_list", + "struct_declaration", "struct_declarator_list", "struct_declarator", + "initializer", "initializer_list", "declaration_statement", "statement", + "simple_statement", "compound_statement", "$@5", "$@6", + "statement_no_new_scope", "statement_scoped", "$@7", "$@8", + "compound_statement_no_new_scope", "statement_list", + "expression_statement", "selection_statement", + "selection_rest_statement", "condition", "switch_statement", "$@9", + "switch_statement_list", "case_label", "iteration_statement", "$@10", + "$@11", "$@12", "for_init_statement", "conditionopt", + "for_rest_statement", "jump_statement", "translation_unit", + "external_declaration", "function_definition", "$@13", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, + 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, + 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473 +}; +# endif + +#define YYPACT_NINF -446 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-446))) + +#define YYTABLE_NINF -328 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 1947, -446, -446, -446, -446, -446, -446, -446, -446, -135, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -120, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -131, -446, -446, -446, -446, -446, -446, -446, + -80, -446, -140, -114, -34, -39, 3112, -146, -446, -3, + -446, -446, -446, -446, 2339, -446, -446, -446, -31, -446, + -446, 486, -446, -446, -1, -37, -30, -446, 4557, -148, + -446, -446, -29, -446, 3112, -446, -446, -446, 3112, 1, + 4, -446, -163, -109, -446, -446, -446, 3461, -23, -446, + -446, -446, -141, -446, -28, -102, -446, -446, 3112, -27, + -446, -147, 699, -446, -446, -446, -446, -31, -164, -446, + 3645, -160, -446, 8, -446, -129, -446, -446, -446, -446, + -446, -446, 4195, 4195, 4195, -446, -446, -446, -446, -446, + -446, -446, -123, -446, -446, -446, -19, -99, 4376, -16, + -446, 4195, -63, -72, -128, -150, -58, -36, -33, -25, + 2, -2, -152, -446, -13, -446, 3830, -446, 27, 4195, + -446, -37, 3112, 3112, 32, 2533, -446, -446, -446, -5, + -4, -446, 7, 9, 3, 4014, 12, 4195, 10, 14, + 15, -446, -446, -105, -446, -446, -104, -446, -114, 16, + -446, -446, -446, -446, 912, -446, -446, -446, -446, -446, + -446, -23, 3645, -127, 3645, -446, -446, 3645, 3112, -446, + 36, -446, -446, -446, -86, -446, -446, 4195, 39, -446, + -446, 4195, 18, -446, -446, -446, 4195, 4195, 4195, 4195, + 4195, 4195, 4195, 4195, 4195, 4195, 4195, 4195, 4195, 4195, + 4195, 4195, 4195, 4195, 4195, -446, -446, -446, 20, -446, + -446, -446, 2726, 32, -31, -100, -446, -446, -446, -446, + -446, 1125, -446, 4195, -446, -446, -88, 4195, -52, -446, + -446, -446, 1125, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, 4195, 4195, -446, -446, -446, -446, + 3645, -446, -62, -446, 2919, -446, -446, 21, 22, -446, + -446, -446, -446, -446, -63, -63, -72, -72, -128, -128, + -128, -128, -150, -150, -58, -36, -33, -25, 2, -2, + 4195, -446, -446, -78, -23, 32, -446, 44, 1749, -84, + -446, -83, -446, 2141, 1125, -446, -446, -446, -446, 3275, + -446, -446, -49, -446, -446, 25, -446, -446, 2141, 23, + -446, 22, 56, 3112, 30, 29, -446, -446, 4195, 4195, + -446, 26, 34, 209, 35, 1551, -446, 37, 31, 1338, + -446, -446, -81, 4195, 1338, 23, -446, -446, 1125, 3645, + -446, -446, -446, 28, 22, -446, -446, 1125, 38, -446, + -446, -446 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 143, 144, 142, 174, 170, 171, 172, 173, 159, + 181, 182, 183, 184, 185, 186, 187, 188, 189, 175, + 176, 177, 190, 191, 192, 148, 146, 147, 145, 151, + 149, 150, 152, 153, 154, 155, 156, 157, 158, 178, + 179, 180, 202, 203, 204, 126, 125, 124, 0, 193, + 194, 195, 196, 197, 198, 199, 200, 201, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 228, + 229, 230, 231, 232, 233, 235, 236, 237, 238, 239, + 240, 242, 243, 244, 245, 246, 247, 248, 226, 227, + 234, 241, 249, 250, 251, 252, 253, 254, 288, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 0, 169, 290, 123, 133, 291, 292, 293, + 0, 368, 0, 369, 0, 100, 99, 0, 111, 116, + 140, 139, 137, 141, 0, 134, 136, 121, 163, 138, + 289, 0, 365, 367, 0, 0, 0, 296, 0, 0, + 88, 85, 0, 98, 0, 107, 101, 109, 0, 110, + 0, 86, 117, 0, 91, 135, 122, 0, 164, 1, + 366, 161, 0, 132, 130, 0, 128, 294, 0, 0, + 89, 0, 0, 370, 102, 106, 108, 104, 112, 103, + 0, 118, 94, 0, 92, 0, 2, 6, 7, 4, + 5, 8, 0, 0, 0, 165, 34, 33, 35, 32, + 3, 10, 28, 12, 17, 18, 0, 0, 22, 0, + 36, 0, 40, 43, 46, 51, 54, 56, 58, 60, + 62, 64, 66, 84, 0, 26, 0, 160, 0, 0, + 127, 0, 0, 0, 0, 0, 298, 87, 90, 0, + 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, + 322, 331, 335, 36, 69, 82, 0, 311, 0, 121, + 314, 333, 313, 312, 0, 315, 316, 317, 318, 319, + 320, 105, 0, 113, 0, 306, 120, 0, 0, 96, + 0, 93, 29, 30, 0, 14, 15, 0, 0, 20, + 19, 0, 169, 23, 25, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 67, 166, 167, 0, 162, + 131, 129, 0, 0, 304, 0, 302, 297, 299, 361, + 360, 0, 352, 0, 364, 362, 0, 0, 0, 347, + 348, 321, 0, 72, 73, 75, 74, 77, 78, 79, + 80, 81, 76, 71, 0, 0, 336, 332, 334, 115, + 0, 309, 0, 119, 0, 97, 9, 0, 16, 13, + 24, 37, 38, 39, 42, 41, 44, 45, 49, 50, + 47, 48, 52, 53, 55, 57, 59, 61, 63, 65, + 0, 168, 295, 0, 305, 0, 300, 0, 0, 0, + 363, 0, 346, 0, 323, 70, 83, 114, 307, 0, + 95, 11, 0, 301, 303, 0, 355, 354, 357, 329, + 342, 340, 0, 0, 0, 0, 308, 310, 0, 0, + 356, 0, 0, 339, 0, 0, 337, 0, 0, 0, + 324, 68, 0, 358, 0, 329, 328, 330, 344, 0, + 326, 349, 325, 0, 359, 353, 338, 345, 0, 341, + 351, 343 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -446, -446, -446, -446, -446, -446, -446, -446, -446, -446, + -446, -446, -14, -446, -204, -193, -221, -196, -121, -118, + -116, -122, -117, -115, -446, -183, -446, -215, -446, -227, + -139, 6, -446, -446, -446, 11, -446, -446, -446, 45, + 54, 52, -446, -446, -422, -446, -446, -446, -446, -26, + -446, -155, -162, -446, -446, 0, -175, -446, 91, -446, + -446, -446, -256, -267, -119, -192, -302, -446, -191, -301, + -445, -228, -446, -446, -236, -235, -446, -446, 69, -369, + -184, -446, -446, -201, -446, -446, -446, -446, -446, -446, + -446, -446, -446, -446, -446, -446, -446, 87, -446, -446 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 240, 241, 242, 407, 243, 244, 245, 246, 247, + 248, 249, 293, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 294, 430, 295, 394, 296, + 264, 297, 152, 318, 225, 298, 154, 155, 156, 185, + 186, 187, 157, 158, 159, 160, 161, 162, 205, 206, + 163, 164, 165, 166, 202, 265, 198, 168, 169, 170, + 272, 208, 275, 276, 365, 366, 316, 402, 300, 301, + 302, 303, 382, 465, 491, 473, 474, 475, 492, 304, + 305, 306, 476, 464, 307, 477, 498, 308, 309, 443, + 371, 438, 458, 471, 472, 310, 171, 172, 173, 182 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 167, 188, 195, 398, 211, 315, 151, 324, 368, 203, + 399, 153, 401, 444, 263, 403, 362, 221, 179, 343, + 344, 462, 354, 219, 197, 197, 195, 176, 266, 188, + 487, 312, 220, 333, 490, 317, 462, 341, 342, 490, + 197, 266, 311, 313, 325, 326, 267, 190, 210, 278, + 191, 174, 268, 273, 345, 346, 180, 355, 376, 177, + 378, 266, 404, -27, 320, 327, 175, 321, 400, 328, + 437, 383, 384, 385, 386, 387, 388, 389, 390, 391, + 392, 222, 181, 263, 223, 270, 263, 224, 330, 395, + 393, 271, 396, 435, 331, 368, 436, 315, 447, 315, + 408, 406, 315, 459, 460, 395, 493, 395, 440, 395, + 395, 195, 395, 347, 348, 435, 410, 273, 453, 497, + 273, 204, 418, 419, 420, 421, 339, 358, 340, 448, + 360, 449, 147, 148, 149, 414, 415, 368, 336, 337, + 338, 395, 442, 398, 395, 468, 439, 467, 416, 417, + 441, 422, 423, 183, 184, 192, 189, 197, 201, 217, + 207, 212, 218, 273, 196, 266, 319, 269, 329, 277, + 334, 167, 349, 353, 350, 352, 356, 151, 209, 445, + 446, 351, 153, 250, 189, 315, 359, 499, 189, 434, + 364, 369, 370, 372, 405, 373, 398, 409, 377, 374, + 380, 455, -26, 452, 379, -21, 381, 273, 274, 431, + 451, 469, 299, -327, 478, 395, 461, 479, 322, 323, + 480, 484, 483, 485, 500, 290, 489, 488, 424, 501, + 427, 461, 425, 215, 315, 426, 428, 335, 214, 429, + 216, 178, 482, 454, 433, 361, 486, 456, 495, 273, + 496, 213, 250, 481, 457, 250, 494, 470, 200, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 274, 363, 315, 274, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 463, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 195, 0, 463, 299, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 274, 0, + 0, 0, 411, 412, 413, 250, 250, 250, 250, 250, + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 274, 0, 0, 0, 0, 0, 0, 0, + 0, 299, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 299, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 274, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 299, 0, + 0, 0, 0, 299, 299, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 299, 0, + 0, 0, 0, 196, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 299, 0, 0, 0, 299, + 0, 0, 0, 0, 299, 0, 199, 0, 299, 1, + 2, 3, 4, 5, 6, 7, 8, 299, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 0, 0, 144, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 145, 146, 147, 148, + 149, 150, 1, 2, 3, 4, 5, 6, 7, 8, + 279, 280, 281, 0, 282, 283, 284, 285, 286, 287, + 288, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 289, 226, 144, 227, + 228, 229, 230, 231, 0, 0, 232, 233, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 234, 0, 0, 0, 290, + 291, 0, 0, 0, 0, 292, 236, 237, 238, 239, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, + 146, 147, 148, 149, 150, 1, 2, 3, 4, 5, + 6, 7, 8, 279, 280, 281, 0, 282, 283, 284, + 285, 286, 287, 288, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 289, + 226, 144, 227, 228, 229, 230, 231, 0, 0, 232, + 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 234, 0, + 0, 0, 290, 397, 0, 0, 0, 0, 292, 236, + 237, 238, 239, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 145, 146, 147, 148, 149, 150, 1, 2, + 3, 4, 5, 6, 7, 8, 279, 280, 281, 0, + 282, 283, 284, 285, 286, 287, 288, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 289, 226, 144, 227, 228, 229, 230, 231, + 0, 0, 232, 233, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 234, 0, 0, 0, 290, 0, 0, 0, 0, + 0, 292, 236, 237, 238, 239, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 145, 146, 147, 148, 149, + 150, 1, 2, 3, 4, 5, 6, 7, 8, 279, + 280, 281, 0, 282, 283, 284, 285, 286, 287, 288, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 289, 226, 144, 227, 228, + 229, 230, 231, 0, 0, 232, 233, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 234, 0, 0, 0, 212, 0, + 0, 0, 0, 0, 292, 236, 237, 238, 239, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 145, 146, + 147, 148, 149, 150, 1, 2, 3, 4, 5, 6, + 7, 8, 279, 280, 281, 0, 282, 283, 284, 285, + 286, 287, 288, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 289, 226, + 144, 227, 228, 229, 230, 231, 0, 0, 232, 233, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 292, 236, 237, + 238, 239, 1, 2, 3, 4, 5, 6, 7, 8, + 0, 145, 146, 147, 148, 149, 150, 0, 0, 0, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 0, 226, 144, 227, + 228, 229, 230, 231, 0, 0, 232, 233, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 292, 236, 237, 238, 239, + 1, 2, 3, 4, 5, 6, 7, 8, 0, 145, + 146, 147, 148, 149, 150, 0, 0, 0, 0, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 0, 0, 144, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 0, 0, 0, 0, 145, 146, 147, + 148, 149, 150, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 0, 226, + 144, 227, 228, 229, 230, 231, 0, 0, 232, 233, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 236, 237, + 238, 239, 1, 2, 3, 4, 5, 6, 7, 8, + 0, 145, 146, 147, 148, 149, 0, 0, 0, 0, + 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 0, 193, 144, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 194, 1, 2, 3, 4, + 5, 6, 7, 8, 0, 0, 0, 0, 0, 145, + 146, 147, 148, 149, 0, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 0, 0, 144, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 367, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, + 0, 0, 0, 145, 146, 147, 148, 149, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 0, 0, 144, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 432, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 0, 0, 0, 0, 0, 0, 145, 146, 147, 148, + 149, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 0, 0, 144, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 450, 0, 0, 0, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 0, 0, 0, 0, 0, 145, + 146, 147, 148, 149, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 0, + 0, 144, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4, 5, 6, 7, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 145, 146, 147, 148, 149, 39, 40, 41, + 42, 43, 44, 0, 0, 0, 0, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 0, 226, 144, 227, 228, 229, 230, 231, + 0, 0, 232, 233, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 234, 0, 0, 0, 314, 466, 4, 5, 6, + 7, 8, 236, 237, 238, 239, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 39, 40, 41, 42, 43, 44, 0, + 0, 0, 0, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 0, 226, + 144, 227, 228, 229, 230, 231, 0, 0, 232, 233, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 234, 0, 0, + 235, 4, 5, 6, 7, 8, 0, 0, 236, 237, + 238, 239, 0, 0, 0, 0, 0, 0, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 39, 40, 41, + 42, 43, 44, 0, 0, 0, 0, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 0, 226, 144, 227, 228, 229, 230, 231, + 0, 0, 232, 233, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 234, 0, 0, 0, 314, 4, 5, 6, 7, + 8, 0, 236, 237, 238, 239, 0, 0, 0, 0, + 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 39, 40, 41, 42, 43, 44, 0, 0, + 0, 0, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 0, 226, 144, + 227, 228, 229, 230, 231, 0, 0, 232, 233, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 234, 0, 0, 357, + 4, 5, 6, 7, 8, 0, 0, 236, 237, 238, + 239, 0, 0, 0, 0, 0, 0, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 39, 40, 41, 42, + 43, 44, 0, 0, 0, 0, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 0, 226, 144, 227, 228, 229, 230, 231, 0, + 0, 232, 233, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 234, 4, 5, 6, 7, 8, 0, 0, 0, 0, + 375, 236, 237, 238, 239, 0, 0, 0, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 39, 40, 41, + 42, 43, 44, 0, 0, 0, 0, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 0, 226, 144, 227, 228, 229, 230, 231, + 0, 0, 232, 233, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 234, 4, 5, 6, 7, 8, 0, 0, 0, + 0, 0, 236, 237, 238, 239, 0, 0, 0, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, + 41, 42, 43, 44, 0, 0, 0, 0, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 332, 0, 226, 144, 227, 228, 229, 230, + 231, 0, 0, 232, 233, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 234, 4, 5, 6, 7, 8, 0, 0, + 0, 0, 0, 236, 237, 238, 239, 0, 0, 0, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, + 40, 41, 42, 43, 44, 0, 0, 0, 0, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 0, 0, 144 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 156, 164, 304, 179, 220, 0, 234, 275, 46, + 312, 0, 314, 382, 197, 317, 272, 192, 158, 169, + 170, 443, 174, 186, 188, 188, 188, 158, 188, 184, + 475, 195, 195, 248, 479, 195, 458, 165, 166, 484, + 188, 188, 217, 218, 167, 168, 187, 193, 196, 196, + 196, 186, 193, 208, 204, 205, 196, 209, 285, 190, + 287, 188, 318, 186, 193, 188, 186, 196, 195, 192, + 371, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 190, 196, 266, 193, 187, 269, 196, 187, 193, + 195, 193, 196, 193, 193, 362, 196, 312, 400, 314, + 327, 187, 317, 187, 187, 193, 187, 193, 196, 193, + 193, 273, 193, 171, 172, 193, 331, 272, 196, 488, + 275, 158, 343, 344, 345, 346, 198, 266, 200, 191, + 269, 193, 212, 213, 214, 339, 340, 404, 201, 202, + 203, 193, 194, 444, 193, 194, 373, 449, 341, 342, + 377, 347, 348, 187, 193, 158, 156, 188, 159, 158, + 190, 190, 158, 318, 164, 188, 158, 195, 187, 196, + 186, 171, 208, 175, 207, 173, 189, 171, 178, 394, + 395, 206, 171, 197, 184, 400, 159, 489, 188, 364, + 158, 196, 196, 186, 158, 186, 497, 158, 186, 196, + 186, 157, 186, 430, 194, 187, 191, 362, 208, 189, + 189, 186, 212, 190, 158, 193, 443, 187, 232, 233, + 191, 187, 196, 14, 196, 190, 195, 190, 349, 191, + 352, 458, 350, 188, 449, 351, 353, 251, 184, 354, + 188, 150, 469, 435, 363, 271, 474, 438, 484, 404, + 485, 182, 266, 468, 438, 269, 483, 458, 171, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 272, 273, 489, 275, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 443, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 463, -1, 458, 304, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 318, -1, + -1, -1, 336, 337, 338, 339, 340, 341, 342, 343, + 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, + 354, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 362, -1, -1, -1, -1, -1, -1, -1, + -1, 371, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 382, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 404, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 438, -1, + -1, -1, -1, 443, 444, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 458, -1, + -1, -1, -1, 463, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 475, -1, -1, -1, 479, + -1, -1, -1, -1, 484, -1, 0, -1, 488, 3, + 4, 5, 6, 7, 8, 9, 10, 497, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, -1, -1, 159, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 210, 211, 212, 213, + 214, 215, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, -1, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, -1, -1, 167, 168, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 186, -1, -1, -1, 190, + 191, -1, -1, -1, -1, 196, 197, 198, 199, 200, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 210, + 211, 212, 213, 214, 215, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, -1, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, + 158, 159, 160, 161, 162, 163, 164, -1, -1, 167, + 168, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 186, -1, + -1, -1, 190, 191, -1, -1, -1, -1, 196, 197, + 198, 199, 200, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 210, 211, 212, 213, 214, 215, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + -1, -1, 167, 168, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 186, -1, -1, -1, 190, -1, -1, -1, -1, + -1, 196, 197, 198, 199, 200, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 210, 211, 212, 213, 214, + 215, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, -1, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, -1, -1, 167, 168, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 186, -1, -1, -1, 190, -1, + -1, -1, -1, -1, 196, 197, 198, 199, 200, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 210, 211, + 212, 213, 214, 215, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, -1, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, + 159, 160, 161, 162, 163, 164, -1, -1, 167, 168, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 186, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 196, 197, 198, + 199, 200, 3, 4, 5, 6, 7, 8, 9, 10, + -1, 210, 211, 212, 213, 214, 215, -1, -1, -1, + -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, -1, 158, 159, 160, + 161, 162, 163, 164, -1, -1, 167, 168, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 186, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 196, 197, 198, 199, 200, + 3, 4, 5, 6, 7, 8, 9, 10, -1, 210, + 211, 212, 213, 214, 215, -1, -1, -1, -1, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, -1, -1, 159, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, + 9, 10, -1, -1, -1, -1, -1, 210, 211, 212, + 213, 214, 215, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, -1, 158, + 159, 160, 161, 162, 163, 164, -1, -1, 167, 168, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 186, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 197, 198, + 199, 200, 3, 4, 5, 6, 7, 8, 9, 10, + -1, 210, 211, 212, 213, 214, -1, -1, -1, -1, + -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, -1, 158, 159, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 196, 3, 4, 5, 6, + 7, 8, 9, 10, -1, -1, -1, -1, -1, 210, + 211, 212, 213, 214, -1, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + -1, -1, 159, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 191, -1, -1, -1, -1, 3, + 4, 5, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, -1, 210, 211, 212, 213, 214, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, -1, -1, 159, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 191, -1, -1, + -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, + -1, -1, -1, -1, -1, -1, 210, 211, 212, 213, + 214, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, + 151, 152, 153, 154, 155, 156, -1, -1, 159, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 191, -1, -1, -1, -1, 3, 4, 5, 6, 7, + 8, 9, 10, -1, -1, -1, -1, -1, -1, 210, + 211, 212, 213, 214, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 151, 152, 153, 154, 155, 156, -1, + -1, 159, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 6, 7, 8, 9, 10, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 210, 211, 212, 213, 214, 52, 53, 54, + 55, 56, 57, -1, -1, -1, -1, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, -1, 158, 159, 160, 161, 162, 163, 164, + -1, -1, 167, 168, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 186, -1, -1, -1, 190, 191, 6, 7, 8, + 9, 10, 197, 198, 199, 200, -1, -1, -1, -1, + -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 52, 53, 54, 55, 56, 57, -1, + -1, -1, -1, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, + 149, 150, 151, 152, 153, 154, 155, 156, -1, 158, + 159, 160, 161, 162, 163, 164, -1, -1, 167, 168, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 186, -1, -1, + 189, 6, 7, 8, 9, 10, -1, -1, 197, 198, + 199, 200, -1, -1, -1, -1, -1, -1, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, + 55, 56, 57, -1, -1, -1, -1, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, -1, 158, 159, 160, 161, 162, 163, 164, + -1, -1, 167, 168, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 186, -1, -1, -1, 190, 6, 7, 8, 9, + 10, -1, 197, 198, 199, 200, -1, -1, -1, -1, + -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 52, 53, 54, 55, 56, 57, -1, -1, + -1, -1, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, -1, 158, 159, + 160, 161, 162, 163, 164, -1, -1, 167, 168, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 186, -1, -1, 189, + 6, 7, 8, 9, 10, -1, -1, 197, 198, 199, + 200, -1, -1, -1, -1, -1, -1, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 52, 53, 54, 55, + 56, 57, -1, -1, -1, -1, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, -1, 158, 159, 160, 161, 162, 163, 164, -1, + -1, 167, 168, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 186, 6, 7, 8, 9, 10, -1, -1, -1, -1, + 196, 197, 198, 199, 200, -1, -1, -1, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 52, 53, 54, + 55, 56, 57, -1, -1, -1, -1, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, -1, 158, 159, 160, 161, 162, 163, 164, + -1, -1, 167, 168, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 186, 6, 7, 8, 9, 10, -1, -1, -1, + -1, -1, 197, 198, 199, 200, -1, -1, -1, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 52, 53, + 54, 55, 56, 57, -1, -1, -1, -1, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, -1, 158, 159, 160, 161, 162, 163, + 164, -1, -1, 167, 168, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 186, 6, 7, 8, 9, 10, -1, -1, + -1, -1, -1, 197, 198, 199, 200, -1, -1, -1, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, + 53, 54, 55, 56, 57, -1, -1, -1, -1, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, -1, -1, 159 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 159, 210, 211, 212, 213, 214, + 215, 250, 251, 254, 255, 256, 257, 261, 262, 263, + 264, 265, 266, 269, 270, 271, 272, 274, 276, 277, + 278, 315, 316, 317, 186, 186, 158, 190, 277, 158, + 196, 196, 318, 187, 193, 258, 259, 260, 270, 274, + 193, 196, 158, 158, 196, 271, 274, 188, 275, 0, + 316, 159, 273, 46, 158, 267, 268, 190, 280, 274, + 196, 275, 190, 297, 259, 258, 260, 158, 158, 186, + 195, 275, 190, 193, 196, 253, 158, 160, 161, 162, + 163, 164, 167, 168, 186, 189, 197, 198, 199, 200, + 220, 221, 222, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 249, 274, 188, 187, 193, 195, + 187, 193, 279, 270, 274, 281, 282, 196, 196, 11, + 12, 13, 15, 16, 17, 18, 19, 20, 21, 157, + 190, 191, 196, 231, 244, 246, 248, 250, 254, 274, + 287, 288, 289, 290, 298, 299, 300, 303, 306, 307, + 314, 275, 195, 275, 190, 246, 285, 195, 252, 158, + 193, 196, 231, 231, 248, 167, 168, 188, 192, 187, + 187, 193, 156, 246, 186, 231, 201, 202, 203, 198, + 200, 165, 166, 169, 170, 204, 205, 171, 172, 208, + 207, 206, 173, 175, 174, 209, 189, 189, 249, 159, + 249, 268, 281, 274, 158, 283, 284, 191, 282, 196, + 196, 309, 186, 186, 196, 196, 248, 186, 248, 194, + 186, 191, 291, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 195, 247, 193, 196, 191, 288, 285, + 195, 285, 286, 285, 281, 158, 187, 223, 248, 158, + 246, 231, 231, 231, 233, 233, 234, 234, 235, 235, + 235, 235, 236, 236, 237, 238, 239, 240, 241, 242, + 245, 189, 191, 283, 275, 193, 196, 288, 310, 248, + 196, 248, 194, 308, 298, 246, 246, 285, 191, 193, + 191, 189, 248, 196, 284, 157, 287, 299, 311, 187, + 187, 248, 263, 270, 302, 292, 191, 285, 194, 186, + 302, 312, 313, 294, 295, 296, 301, 304, 158, 187, + 191, 246, 248, 196, 187, 14, 290, 289, 190, 195, + 289, 293, 297, 187, 248, 293, 294, 298, 305, 285, + 196, 191 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 219, 220, 221, 221, 221, 221, 221, 221, 221, + 222, 222, 222, 222, 222, 222, 223, 224, 225, 226, + 226, 227, 227, 228, 228, 229, 230, 230, 231, 231, + 231, 231, 232, 232, 232, 232, 233, 233, 233, 233, + 234, 234, 234, 235, 235, 235, 236, 236, 236, 236, + 236, 237, 237, 237, 238, 238, 239, 239, 240, 240, + 241, 241, 242, 242, 243, 243, 244, 245, 244, 246, + 246, 247, 247, 247, 247, 247, 247, 247, 247, 247, + 247, 247, 248, 248, 249, 250, 250, 250, 250, 250, + 250, 250, 250, 250, 252, 251, 253, 253, 254, 255, + 255, 256, 256, 257, 258, 258, 259, 259, 259, 259, + 260, 261, 261, 261, 261, 261, 262, 262, 262, 262, + 262, 263, 263, 264, 265, 265, 265, 266, 267, 267, + 268, 268, 268, 269, 270, 270, 271, 271, 271, 271, + 271, 271, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 273, 273, 274, 274, 275, 275, 275, 275, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 277, 277, 277, 279, 278, 280, 278, 281, 281, + 282, 282, 283, 283, 284, 284, 285, 285, 285, 286, + 286, 287, 288, 288, 289, 289, 289, 289, 289, 289, + 289, 290, 291, 292, 290, 293, 293, 295, 294, 296, + 294, 297, 297, 298, 298, 299, 299, 300, 301, 301, + 302, 302, 304, 303, 305, 305, 306, 306, 308, 307, + 309, 307, 310, 307, 311, 311, 312, 312, 313, 313, + 314, 314, 314, 314, 314, 315, 315, 316, 316, 318, + 317 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 4, 1, 3, 2, 2, 1, 1, 1, 2, + 2, 2, 1, 2, 3, 2, 1, 1, 1, 2, + 2, 2, 1, 1, 1, 1, 1, 3, 3, 3, + 1, 3, 3, 1, 3, 3, 1, 3, 3, 3, + 3, 1, 3, 3, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 1, 0, 6, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 2, 2, 4, 2, 3, + 4, 2, 3, 4, 0, 6, 2, 3, 2, 1, + 1, 2, 3, 3, 2, 3, 2, 1, 2, 1, + 1, 1, 3, 4, 6, 5, 1, 2, 3, 5, + 4, 1, 2, 1, 1, 1, 1, 4, 1, 3, + 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 4, 1, 3, 1, 2, 2, 3, 3, 4, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 6, 0, 5, 1, 2, + 3, 4, 1, 3, 1, 2, 1, 3, 4, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 0, 0, 5, 1, 1, 0, 2, 0, + 2, 2, 3, 1, 2, 1, 2, 5, 3, 1, + 1, 4, 0, 8, 0, 1, 3, 2, 0, 6, + 0, 8, 0, 7, 1, 1, 1, 0, 2, 3, + 2, 2, 2, 3, 2, 1, 2, 1, 1, 0, + 3 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (pParseContext, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, pParseContext); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (pParseContext); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, pParseContext); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, glslang::TParseContext* pParseContext) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , pParseContext); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, pParseContext); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, glslang::TParseContext* pParseContext) +{ + YYUSE (yyvaluep); + YYUSE (pParseContext); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (glslang::TParseContext* pParseContext) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, parseContext); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 226 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[0].lex).loc, (yyvsp[0].lex).symbol, (yyvsp[0].lex).string); + } +#line 2823 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 3: +#line 232 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 2831 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 4: +#line 235 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 2839 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 5: +#line 238 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 2848 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 6: +#line 242 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); + } +#line 2856 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 7: +#line 245 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double literal"); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtDouble, (yyvsp[0].lex).loc, true); + } +#line 2865 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 8: +#line 249 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); + } +#line 2873 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 9: +#line 252 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); + if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) + (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); + } +#line 2883 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 10: +#line 260 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 2891 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 11: +#line 263 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[-2].lex).loc, (yyvsp[-3].interm.intermTypedNode), (yyvsp[-1].interm.intermTypedNode)); + } +#line 2899 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 12: +#line 266 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 2907 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 13: +#line 269 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode), *(yyvsp[0].lex).string); + } +#line 2915 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 14: +#line 272 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); + parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "++", (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "++", EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode)); + } +#line 2925 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 15: +#line 277 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); + parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "--", (yyvsp[-1].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "--", EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode)); + } +#line 2935 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 16: +#line 285 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.integerCheck((yyvsp[0].interm.intermTypedNode), "[]"); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 2944 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 17: +#line 292 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[0].interm).loc, (yyvsp[0].interm).function, (yyvsp[0].interm).intermNode); + delete (yyvsp[0].interm).function; + } +#line 2953 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 18: +#line 299 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 2961 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 19: +#line 305 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 2970 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 20: +#line 309 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 2979 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 21: +#line 316 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + } +#line 2987 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 22: +#line 319 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 2995 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 23: +#line 325 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + TParameter param = { 0, new TType }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + (yyvsp[-1].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-1].interm).function; + (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); + } +#line 3007 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 24: +#line 332 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + TParameter param = { 0, new TType }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + (yyvsp[-2].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-2].interm).function; + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + } +#line 3019 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 25: +#line 342 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-1].interm); + } +#line 3027 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 26: +#line 350 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // Constructor + (yyval.interm).intermNode = 0; + (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); + } +#line 3037 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 27: +#line 355 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // + // Should be a method or subroutine call, but we haven't recognized the arguments yet. + // + (yyval.interm).function = 0; + (yyval.interm).intermNode = 0; + + TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode(); + if (method) { + (yyval.interm).function = new TFunction(&method->getMethodName(), TType(EbtInt), EOpArrayLength); + (yyval.interm).intermNode = method->getObject(); + } else { + TIntermSymbol* symbol = (yyvsp[0].interm.intermTypedNode)->getAsSymbolNode(); + if (symbol) { + parseContext.reservedErrorCheck(symbol->getLoc(), symbol->getName()); + TFunction *function = new TFunction(&symbol->getName(), TType(EbtVoid)); + (yyval.interm).function = function; + } else + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "function call, method, or subroutine call expected", "", ""); + } + + if ((yyval.interm).function == 0) { + // error recover + TString empty(""); + (yyval.interm).function = new TFunction(&empty, TType(EbtVoid), EOpNull); + } + } +#line 3069 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 28: +#line 385 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.variableCheck((yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + if (TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode()) + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), ""); + } +#line 3080 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 29: +#line 391 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "++", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "++", EOpPreIncrement, (yyvsp[0].interm.intermTypedNode)); + } +#line 3089 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 30: +#line 395 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "--", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "--", EOpPreDecrement, (yyvsp[0].interm.intermTypedNode)); + } +#line 3098 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 31: +#line 399 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].interm).op != EOpNull) { + char errorOp[2] = {0, 0}; + switch((yyvsp[-1].interm).op) { + case EOpNegative: errorOp[0] = '-'; break; + case EOpLogicalNot: errorOp[0] = '!'; break; + case EOpBitwiseNot: errorOp[0] = '~'; break; + default: break; // some compilers want this + } + (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].interm).loc, errorOp, (yyvsp[-1].interm).op, (yyvsp[0].interm.intermTypedNode)); + } else { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) + (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); + } + } +#line 3119 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 32: +#line 419 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNull; } +#line 3125 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 33: +#line 420 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNegative; } +#line 3131 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 34: +#line 421 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLogicalNot; } +#line 3137 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 35: +#line 422 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpBitwiseNot; + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise not"); } +#line 3144 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 36: +#line 428 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3150 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 37: +#line 429 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "*", EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3160 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 38: +#line 434 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "/", EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3170 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 39: +#line 439 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "%"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "%", EOpMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3181 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 40: +#line 448 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3187 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 41: +#line 449 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "+", EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3197 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 42: +#line 454 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "-", EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3207 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 43: +#line 462 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3213 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 44: +#line 463 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift left"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<<", EOpLeftShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3224 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 45: +#line 469 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift right"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">>", EOpRightShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3235 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 46: +#line 478 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3241 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 47: +#line 479 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<", EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3251 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 48: +#line 484 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">", EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3261 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 49: +#line 489 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<=", EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3271 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 50: +#line 494 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3281 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 51: +#line 502 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3287 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 52: +#line 503 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); + parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "==", EOpEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3299 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 53: +#line 510 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); + parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "!=", EOpNotEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3311 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 54: +#line 520 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3317 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 55: +#line 521 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise and"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&", EOpAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3328 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 56: +#line 530 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3334 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 57: +#line 531 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise exclusive or"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^", EOpExclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3345 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 58: +#line 540 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3351 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 59: +#line 541 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise inclusive or"); + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "|", EOpInclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 3362 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 60: +#line 550 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3368 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 61: +#line 551 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&&", EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3378 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 62: +#line 559 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3384 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 63: +#line 560 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^^", EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3394 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 64: +#line 568 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3400 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 65: +#line 569 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "||", EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + if ((yyval.interm.intermTypedNode) == 0) + (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); + } +#line 3410 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 66: +#line 577 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3416 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 67: +#line 578 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + ++parseContext.controlFlowNestingLevel; + } +#line 3424 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 68: +#line 581 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + --parseContext.controlFlowNestingLevel; + parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-5].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-4].lex).loc, "?", (yyvsp[-5].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addSelection((yyvsp[-5].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-4].lex).loc); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.binaryOpError((yyvsp[-4].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + } +#line 3441 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 69: +#line 596 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } +#line 3447 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 70: +#line 597 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.arrayObjectCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array assignment"); + parseContext.opaqueCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); + parseContext.lValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)); + parseContext.rValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[0].interm.intermTypedNode)); + (yyval.interm.intermTypedNode) = parseContext.intermediate.addAssign((yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].interm).loc); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.assignError((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } + } +#line 3463 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 71: +#line 611 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpAssign; + } +#line 3472 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 72: +#line 615 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpMulAssign; + } +#line 3481 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 73: +#line 619 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpDivAssign; + } +#line 3490 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 74: +#line 623 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "%="); + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpModAssign; + } +#line 3500 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 75: +#line 628 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpAddAssign; + } +#line 3509 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 76: +#line 632 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).op = EOpSubAssign; + } +#line 3518 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 77: +#line 636 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift left assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLeftShiftAssign; + } +#line 3527 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 78: +#line 640 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift right assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpRightShiftAssign; + } +#line 3536 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 79: +#line 644 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-and assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAndAssign; + } +#line 3545 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 80: +#line 648 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-xor assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign; + } +#line 3554 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 81: +#line 652 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-or assign"); + (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign; + } +#line 3563 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 82: +#line 659 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 3571 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 83: +#line 662 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + if ((yyval.interm.intermTypedNode) == 0) { + parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } + } +#line 3583 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 84: +#line 672 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.constantValueCheck((yyvsp[0].interm.intermTypedNode), ""); + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 3592 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 85: +#line 679 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); + (yyval.interm.intermNode) = 0; + // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature + } +#line 3602 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 86: +#line 684 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].interm).intermNode && (yyvsp[-1].interm).intermNode->getAsAggregate()) + (yyvsp[-1].interm).intermNode->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-1].interm).intermNode; + } +#line 3612 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 87: +#line 689 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[-3].lex).loc, ENoProfile, 130, 0, "precision statement"); + + // lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope + parseContext.symbolTable.setPreviousDefaultPrecisions(&parseContext.defaultPrecision[0]); + parseContext.setDefaultPrecision((yyvsp[-3].lex).loc, (yyvsp[-1].interm.type), (yyvsp[-2].interm.type).qualifier.precision); + (yyval.interm.intermNode) = 0; + } +#line 3625 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 88: +#line 697 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.declareBlock((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).typeList); + (yyval.interm.intermNode) = 0; + } +#line 3634 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 89: +#line 701 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.declareBlock((yyvsp[-2].interm).loc, *(yyvsp[-2].interm).typeList, (yyvsp[-1].lex).string); + (yyval.interm.intermNode) = 0; + } +#line 3643 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 90: +#line 705 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.declareBlock((yyvsp[-3].interm).loc, *(yyvsp[-3].interm).typeList, (yyvsp[-2].lex).string, (yyvsp[-1].interm).arraySizes); + (yyval.interm.intermNode) = 0; + } +#line 3652 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 91: +#line 709 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); + parseContext.updateStandaloneQualifierDefaults((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type)); + (yyval.interm.intermNode) = 0; + } +#line 3662 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 92: +#line 714 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.checkNoShaderLayouts((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).shaderQualifiers); + parseContext.addQualifierToExisting((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, *(yyvsp[-1].lex).string); + (yyval.interm.intermNode) = 0; + } +#line 3672 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 93: +#line 719 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); + (yyvsp[-1].interm.identifierList)->push_back((yyvsp[-2].lex).string); + parseContext.addQualifierToExisting((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier, *(yyvsp[-1].interm.identifierList)); + (yyval.interm.intermNode) = 0; + } +#line 3683 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 94: +#line 728 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { parseContext.nestedBlockCheck((yyvsp[-2].interm.type).loc); } +#line 3689 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 95: +#line 728 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + --parseContext.structNestingLevel; + parseContext.blockName = (yyvsp[-4].lex).string; + parseContext.globalQualifierFixCheck((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).qualifier); + parseContext.checkNoShaderLayouts((yyvsp[-5].interm.type).loc, (yyvsp[-5].interm.type).shaderQualifiers); + parseContext.currentBlockQualifier = (yyvsp[-5].interm.type).qualifier; + (yyval.interm).loc = (yyvsp[-5].interm.type).loc; + (yyval.interm).typeList = (yyvsp[-1].interm.typeList); + } +#line 3703 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 96: +#line 739 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.identifierList) = new TIdentifierList; + (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); + } +#line 3712 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 97: +#line 743 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.identifierList) = (yyvsp[-2].interm.identifierList); + (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); + } +#line 3721 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 98: +#line 750 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).function = (yyvsp[-1].interm.function); + (yyval.interm).loc = (yyvsp[0].lex).loc; + } +#line 3730 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 99: +#line 757 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } +#line 3738 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 100: +#line 760 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.function) = (yyvsp[0].interm.function); + } +#line 3746 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 101: +#line 767 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // Add the parameter + (yyval.interm.function) = (yyvsp[-1].interm.function); + if ((yyvsp[0].interm).param.type->getBasicType() != EbtVoid) + (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm).param); + else + delete (yyvsp[0].interm).param.type; + } +#line 3759 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 102: +#line 775 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ((yyvsp[0].interm).param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + parseContext.error((yyvsp[-1].lex).loc, "cannot be an argument type except for '(void)'", "void", ""); + delete (yyvsp[0].interm).param.type; + } else { + // Add the parameter + (yyval.interm.function) = (yyvsp[-2].interm.function); + (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); + } + } +#line 3781 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 103: +#line 795 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].interm.type).qualifier.storage != EvqGlobal && (yyvsp[-2].interm.type).qualifier.storage != EvqTemporary) { + parseContext.error((yyvsp[-1].lex).loc, "no qualifiers allowed for function return", + GetStorageQualifierString((yyvsp[-2].interm.type).qualifier.storage), ""); + } + if ((yyvsp[-2].interm.type).arraySizes) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type((yyvsp[-2].interm.type)); + function = new TFunction((yyvsp[-1].lex).string, type); + (yyval.interm.function) = function; + } +#line 3800 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 104: +#line 813 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-1].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-1].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + parseContext.arraySizeRequiredCheck((yyvsp[-1].interm.type).loc, *(yyvsp[-1].interm.type).arraySizes); + } + if ((yyvsp[-1].interm.type).basicType == EbtVoid) { + parseContext.error((yyvsp[0].lex).loc, "illegal use of type 'void'", (yyvsp[0].lex).string->c_str(), ""); + } + parseContext.reservedErrorCheck((yyvsp[0].lex).loc, *(yyvsp[0].lex).string); + + TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))}; + (yyval.interm).loc = (yyvsp[0].lex).loc; + (yyval.interm).param = param; + } +#line 3820 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 105: +#line 828 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + parseContext.arrayDimCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.type).arraySizes, (yyvsp[0].interm).arraySizes); + + parseContext.arraySizeRequiredCheck((yyvsp[0].interm).loc, *(yyvsp[0].interm).arraySizes); + parseContext.reservedErrorCheck((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string); + + (yyvsp[-2].interm.type).arraySizes = (yyvsp[0].interm).arraySizes; + + TParameter param = { (yyvsp[-1].lex).string, new TType((yyvsp[-2].interm.type))}; + (yyval.interm).loc = (yyvsp[-1].lex).loc; + (yyval.interm).param = param; + } +#line 3842 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 106: +#line 851 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) + (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + + parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); + parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); + + } +#line 3858 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 107: +#line 862 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); + parseContext.paramCheckFix((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + } +#line 3870 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 108: +#line 872 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) + (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; + parseContext.precisionQualifierCheck((yyvsp[-1].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + + parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); + parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); + } +#line 3885 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 109: +#line 882 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + + parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); + parseContext.paramCheckFix((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + } +#line 3897 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 110: +#line 892 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; + (yyval.interm).param = param; + if ((yyvsp[0].interm.type).arraySizes) + parseContext.arraySizeRequiredCheck((yyvsp[0].interm.type).loc, *(yyvsp[0].interm.type).arraySizes); + } +#line 3908 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 111: +#line 901 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[0].interm); + } +#line 3916 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 112: +#line 904 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-2].interm); + parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-2].interm).type); + } +#line 3925 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 113: +#line 908 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-3].interm); + parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-3].interm).type, (yyvsp[0].interm).arraySizes); + } +#line 3934 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 114: +#line 912 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-5].interm).type; + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-5].interm).type, (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-5].interm).intermNode, initNode, (yyvsp[-1].lex).loc); + } +#line 3944 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 115: +#line 917 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-4].interm).type; + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-4].interm).type, 0, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-4].interm).intermNode, initNode, (yyvsp[-1].lex).loc); + } +#line 3954 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 116: +#line 925 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[0].interm.type); + (yyval.interm).intermNode = 0; + parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type); + } +#line 3964 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 117: +#line 930 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-1].interm.type); + (yyval.interm).intermNode = 0; + parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-1].interm.type)); + } +#line 3974 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 118: +#line 935 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-2].interm.type); + (yyval.interm).intermNode = 0; + parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-2].interm.type), (yyvsp[0].interm).arraySizes); + } +#line 3984 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 119: +#line 940 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-4].interm.type); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-4].interm.type), (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); + } +#line 3994 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 120: +#line 945 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).type = (yyvsp[-3].interm.type); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); + } +#line 4004 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 121: +#line 954 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + + parseContext.globalQualifierTypeCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyval.interm.type)); + if ((yyvsp[0].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + } + + parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier); + } +#line 4020 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 122: +#line 965 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); + parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type)); + + if ((yyvsp[0].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + } + + if ((yyvsp[0].interm.type).arraySizes && parseContext.arrayQualifierError((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).qualifier)) + (yyvsp[0].interm.type).arraySizes = 0; + + parseContext.checkNoShaderLayouts((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); + (yyvsp[0].interm.type).shaderQualifiers.merge((yyvsp[-1].interm.type).shaderQualifiers); + parseContext.mergeQualifiers((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyvsp[-1].interm.type).qualifier, true); + parseContext.precisionQualifierCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).basicType, (yyvsp[0].interm.type).qualifier); + + (yyval.interm.type) = (yyvsp[0].interm.type); + + if (! (yyval.interm.type).qualifier.isInterpolation() && + ((parseContext.language == EShLangVertex && (yyval.interm.type).qualifier.storage == EvqVaryingOut) || + (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn))) + (yyval.interm.type).qualifier.smooth = true; + } +#line 4049 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 123: +#line 992 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "invariant"); + parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.invariant = true; + } +#line 4060 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 124: +#line 1001 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "smooth"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "smooth"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "smooth"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.smooth = true; + } +#line 4072 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 125: +#line 1008 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "flat"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "flat"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "flat"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.flat = true; + } +#line 4084 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 126: +#line 1015 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "noperspective"); + parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "noperspective"); + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "noperspective"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.nopersp = true; + } +#line 4096 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 127: +#line 1025 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[-1].interm.type); + } +#line 4104 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 128: +#line 1031 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4112 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 129: +#line 1034 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[-2].interm.type); + (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); + parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); + } +#line 4122 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 130: +#line 1041 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), *(yyvsp[0].lex).string); + } +#line 4131 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 131: +#line 1045 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[-2].lex).loc); + parseContext.setLayoutQualifier((yyvsp[-2].lex).loc, (yyval.interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode)); + } +#line 4140 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 132: +#line 1049 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { // because "shared" is both an identifier and a keyword + (yyval.interm.type).init((yyvsp[0].lex).loc); + TString strShared("shared"); + parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), strShared); + } +#line 4150 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 133: +#line 1057 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + } +#line 4158 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 134: +#line 1063 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4166 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 135: +#line 1066 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[-1].interm.type); + if ((yyval.interm.type).basicType == EbtVoid) + (yyval.interm.type).basicType = (yyvsp[0].interm.type).basicType; + + (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); + parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); + } +#line 4179 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 136: +#line 1077 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4187 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 137: +#line 1080 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4195 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 138: +#line 1083 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4203 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 139: +#line 1086 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4212 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 140: +#line 1090 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4221 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 141: +#line 1094 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // allow inheritance of storage qualifier from block declaration + (yyval.interm.type) = (yyvsp[0].interm.type); + } +#line 4230 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 142: +#line 1101 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant + } +#line 4239 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 143: +#line 1105 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangVertex, "attribute"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "attribute"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "attribute"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "attribute"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "attribute"); + + parseContext.globalCheck((yyvsp[0].lex).loc, "attribute"); + + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqVaryingIn; + } +#line 4256 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 144: +#line 1117 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "varying"); + parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "varying"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, ECoreProfile, 420, "varying"); + parseContext.requireNotRemoved((yyvsp[0].lex).loc, EEsProfile, 300, "varying"); + + parseContext.globalCheck((yyvsp[0].lex).loc, "varying"); + + (yyval.interm.type).init((yyvsp[0].lex).loc); + if (parseContext.language == EShLangVertex) + (yyval.interm.type).qualifier.storage = EvqVaryingOut; + else + (yyval.interm.type).qualifier.storage = EvqVaryingIn; + } +#line 4275 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 145: +#line 1131 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "inout"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqInOut; + } +#line 4285 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 146: +#line 1136 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "in"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later + (yyval.interm.type).qualifier.storage = EvqIn; + } +#line 4296 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 147: +#line 1142 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "out"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later + (yyval.interm.type).qualifier.storage = EvqOut; + } +#line 4307 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 148: +#line 1148 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 120, 0, "centroid"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "centroid"); + parseContext.globalCheck((yyvsp[0].lex).loc, "centroid"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.centroid = true; + } +#line 4319 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 149: +#line 1155 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "patch"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.patch = true; + } +#line 4330 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 150: +#line 1161 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "sample"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.sample = true; + } +#line 4340 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 151: +#line 1166 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "uniform"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqUniform; + } +#line 4350 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 152: +#line 1171 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "buffer"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqBuffer; + } +#line 4360 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 153: +#line 1176 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, 430, 0, "shared"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 310, 0, "shared"); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangCompute, "shared"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqShared; + } +#line 4372 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 154: +#line 1183 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.coherent = true; + } +#line 4381 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 155: +#line 1187 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.volatil = true; + } +#line 4390 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 156: +#line 1191 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.restrict = true; + } +#line 4399 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 157: +#line 1195 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.readonly = true; + } +#line 4408 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 158: +#line 1199 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.writeonly = true; + } +#line 4417 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 159: +#line 1203 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[0].lex).loc, "subroutine"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqUniform; + } +#line 4427 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 160: +#line 1208 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalCheck((yyvsp[-3].lex).loc, "subroutine"); + (yyval.interm.type).init((yyvsp[-3].lex).loc); + (yyval.interm.type).qualifier.storage = EvqUniform; + // TODO: 4.0 semantics: subroutines + // 1) make sure each identifier is a type declared earlier with SUBROUTINE + // 2) save all of the identifiers for future comparison with the declared function + } +#line 4440 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 161: +#line 1219 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // TODO: 4.0 functionality: subroutine type to list + } +#line 4448 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 162: +#line 1222 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + } +#line 4455 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 163: +#line 1227 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); + } +#line 4464 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 164: +#line 1231 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.arrayDimCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes, 0); + (yyval.interm.type) = (yyvsp[-1].interm.type); + (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); + (yyval.interm.type).arraySizes = (yyvsp[0].interm).arraySizes; + } +#line 4475 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 165: +#line 1240 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[-1].lex).loc; + (yyval.interm).arraySizes = new TArraySizes; + (yyval.interm).arraySizes->addInnerSize(); + } +#line 4485 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 166: +#line 1245 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm).loc = (yyvsp[-2].lex).loc; + (yyval.interm).arraySizes = new TArraySizes; + + int size; + parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size); + (yyval.interm).arraySizes->addInnerSize(size); + } +#line 4498 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 167: +#line 1253 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-2].interm); + (yyval.interm).arraySizes->addInnerSize(); + } +#line 4507 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 168: +#line 1257 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm) = (yyvsp[-3].interm); + + int size; + parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size); + (yyval.interm).arraySizes->addInnerSize(size); + } +#line 4519 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 169: +#line 1267 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtVoid; + } +#line 4528 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 170: +#line 1271 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + } +#line 4537 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 171: +#line 1275 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + } +#line 4547 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 172: +#line 1280 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + } +#line 4556 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 173: +#line 1284 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + } +#line 4566 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 174: +#line 1289 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + } +#line 4575 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 175: +#line 1293 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 4585 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 176: +#line 1298 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 4595 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 177: +#line 1303 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 4605 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 178: +#line 1308 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 4616 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 179: +#line 1314 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 4627 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 180: +#line 1320 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 4638 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 181: +#line 1326 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(2); + } +#line 4648 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 182: +#line 1331 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(3); + } +#line 4658 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 183: +#line 1336 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(4); + } +#line 4668 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 184: +#line 1341 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(2); + } +#line 4678 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 185: +#line 1346 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(3); + } +#line 4688 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 186: +#line 1351 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt; + (yyval.interm.type).setVector(4); + } +#line 4698 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 187: +#line 1356 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 4709 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 188: +#line 1362 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 4720 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 189: +#line 1368 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(4); + } +#line 4731 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 190: +#line 1374 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 4741 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 191: +#line 1379 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 4751 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 192: +#line 1384 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 4761 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 193: +#line 1389 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 2); + } +#line 4771 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 194: +#line 1394 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 3); + } +#line 4781 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 195: +#line 1399 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(2, 4); + } +#line 4791 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 196: +#line 1404 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 2); + } +#line 4801 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 197: +#line 1409 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 3); + } +#line 4811 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 198: +#line 1414 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(3, 4); + } +#line 4821 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 199: +#line 1419 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 2); + } +#line 4831 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 200: +#line 1424 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 3); + } +#line 4841 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 201: +#line 1429 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setMatrix(4, 4); + } +#line 4851 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 202: +#line 1434 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 4862 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 203: +#line 1440 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 4873 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 204: +#line 1446 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 4884 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 205: +#line 1452 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 4895 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 206: +#line 1458 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 3); + } +#line 4906 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 207: +#line 1464 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 4); + } +#line 4917 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 208: +#line 1470 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 2); + } +#line 4928 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 209: +#line 1476 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 4939 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 210: +#line 1482 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 4); + } +#line 4950 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 211: +#line 1488 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 2); + } +#line 4961 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 212: +#line 1494 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 3); + } +#line 4972 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 213: +#line 1500 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 4983 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 214: +#line 1506 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtAtomicUint; + } +#line 4992 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 215: +#line 1510 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D); + } +#line 5002 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 216: +#line 1515 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D); + } +#line 5012 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 217: +#line 1520 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd3D); + } +#line 5022 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 218: +#line 1525 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube); + } +#line 5032 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 219: +#line 1530 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true); + } +#line 5042 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 220: +#line 1535 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true); + } +#line 5052 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 221: +#line 1540 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true); + } +#line 5062 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 222: +#line 1545 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true); + } +#line 5072 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 223: +#line 1550 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true); + } +#line 5082 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 224: +#line 1555 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true); + } +#line 5092 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 225: +#line 1560 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true); + } +#line 5102 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 226: +#line 1565 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true); + } +#line 5112 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 227: +#line 1570 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true); + } +#line 5122 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 228: +#line 1575 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd1D); + } +#line 5132 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 229: +#line 1580 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D); + } +#line 5142 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 230: +#line 1585 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd3D); + } +#line 5152 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 231: +#line 1590 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdCube); + } +#line 5162 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 232: +#line 1595 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd1D, true); + } +#line 5172 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 233: +#line 1600 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, true); + } +#line 5182 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 234: +#line 1605 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdCube, true); + } +#line 5192 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 235: +#line 1610 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd1D); + } +#line 5202 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 236: +#line 1615 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D); + } +#line 5212 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 237: +#line 1620 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd3D); + } +#line 5222 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 238: +#line 1625 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdCube); + } +#line 5232 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 239: +#line 1630 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd1D, true); + } +#line 5242 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 240: +#line 1635 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, true); + } +#line 5252 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 241: +#line 1640 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdCube, true); + } +#line 5262 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 242: +#line 1645 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdRect); + } +#line 5272 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 243: +#line 1650 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true); + } +#line 5282 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 244: +#line 1655 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdRect); + } +#line 5292 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 245: +#line 1660 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdRect); + } +#line 5302 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 246: +#line 1665 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer); + } +#line 5312 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 247: +#line 1670 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, EsdBuffer); + } +#line 5322 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 248: +#line 1675 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, EsdBuffer); + } +#line 5332 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 249: +#line 1680 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true); + } +#line 5342 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 250: +#line 1685 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true); + } +#line 5352 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 251: +#line 1690 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true); + } +#line 5362 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 252: +#line 1695 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true); + } +#line 5372 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 253: +#line 1700 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true); + } +#line 5382 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 254: +#line 1705 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true); + } +#line 5392 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 255: +#line 1710 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D); + } +#line 5402 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 256: +#line 1715 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd1D); + } +#line 5412 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 257: +#line 1720 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd1D); + } +#line 5422 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 258: +#line 1725 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D); + } +#line 5432 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 259: +#line 1730 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D); + } +#line 5442 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 260: +#line 1735 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D); + } +#line 5452 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 261: +#line 1740 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D); + } +#line 5462 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 262: +#line 1745 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd3D); + } +#line 5472 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 263: +#line 1750 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd3D); + } +#line 5482 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 264: +#line 1755 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect); + } +#line 5492 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 265: +#line 1760 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdRect); + } +#line 5502 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 266: +#line 1765 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdRect); + } +#line 5512 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 267: +#line 1770 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube); + } +#line 5522 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 268: +#line 1775 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdCube); + } +#line 5532 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 269: +#line 1780 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdCube); + } +#line 5542 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 270: +#line 1785 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer); + } +#line 5552 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 271: +#line 1790 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer); + } +#line 5562 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 272: +#line 1795 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer); + } +#line 5572 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 273: +#line 1800 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true); + } +#line 5582 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 274: +#line 1805 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true); + } +#line 5592 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 275: +#line 1810 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true); + } +#line 5602 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 276: +#line 1815 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true); + } +#line 5612 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 277: +#line 1820 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true); + } +#line 5622 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 278: +#line 1825 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true); + } +#line 5632 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 279: +#line 1830 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true); + } +#line 5642 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 280: +#line 1835 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true); + } +#line 5652 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 281: +#line 1840 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true); + } +#line 5662 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 282: +#line 1845 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true); + } +#line 5672 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 283: +#line 1850 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true); + } +#line 5682 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 284: +#line 1855 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true); + } +#line 5692 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 285: +#line 1860 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true); + } +#line 5702 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 286: +#line 1865 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true); + } +#line 5712 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 287: +#line 1870 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true); + } +#line 5722 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 288: +#line 1875 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { // GL_OES_EGL_image_external + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.set(EbtFloat, Esd2D); + (yyval.interm.type).sampler.external = true; + } +#line 5733 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 289: +#line 1881 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.type) = (yyvsp[0].interm.type); + (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type)); + } +#line 5743 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 290: +#line 1886 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + if (const TVariable* variable = ((yyvsp[0].lex).symbol)->getAsVariable()) { + const TType& structure = variable->getType(); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = &structure; + } else + parseContext.error((yyvsp[0].lex).loc, "expected type name", (yyvsp[0].lex).string->c_str(), ""); + } +#line 5761 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 291: +#line 1902 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "highp precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + if (parseContext.profile == EEsProfile) + (yyval.interm.type).qualifier.precision = EpqHigh; + } +#line 5772 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 292: +#line 1908 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + if (parseContext.profile == EEsProfile) + (yyval.interm.type).qualifier.precision = EpqMedium; + } +#line 5783 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 293: +#line 1914 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + if (parseContext.profile == EEsProfile) + (yyval.interm.type).qualifier.precision = EpqLow; + } +#line 5794 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 294: +#line 1923 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { parseContext.nestedStructCheck((yyvsp[-2].lex).loc); } +#line 5800 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 295: +#line 1923 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + TType* structure = new TType((yyvsp[-1].interm.typeList), *(yyvsp[-4].lex).string); + parseContext.structArrayCheck((yyvsp[-4].lex).loc, *structure); + TVariable* userTypeDef = new TVariable((yyvsp[-4].lex).string, *structure, true); + if (! parseContext.symbolTable.insert(*userTypeDef)) + parseContext.error((yyvsp[-4].lex).loc, "redefinition", (yyvsp[-4].lex).string->c_str(), "struct"); + (yyval.interm.type).init((yyvsp[-5].lex).loc); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = structure; + --parseContext.structNestingLevel; + } +#line 5816 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 296: +#line 1934 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { parseContext.nestedStructCheck((yyvsp[-1].lex).loc); } +#line 5822 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 297: +#line 1934 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + TType* structure = new TType((yyvsp[-1].interm.typeList), TString("")); + (yyval.interm.type).init((yyvsp[-4].lex).loc); + (yyval.interm.type).basicType = EbtStruct; + (yyval.interm.type).userDef = structure; + --parseContext.structNestingLevel; + } +#line 5834 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 298: +#line 1944 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.typeList) = (yyvsp[0].interm.typeList); + } +#line 5842 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 299: +#line 1947 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + for (unsigned int i = 0; i < (yyvsp[0].interm.typeList)->size(); ++i) { + for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) { + if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[0].interm.typeList))[i].type->getFieldName()) + parseContext.error((*(yyvsp[0].interm.typeList))[i].loc, "duplicate member name:", "", (*(yyvsp[0].interm.typeList))[i].type->getFieldName().c_str()); + } + (yyval.interm.typeList)->push_back((*(yyvsp[0].interm.typeList))[i]); + } + } +#line 5857 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 300: +#line 1960 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + if (parseContext.profile == EEsProfile) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + + parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + + for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { + parseContext.arrayDimCheck((yyvsp[-2].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[-2].interm.type).arraySizes); + (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[-2].interm.type)); + } + } +#line 5880 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 301: +#line 1978 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.globalQualifierFixCheck((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier); + if ((yyvsp[-2].interm.type).arraySizes) { + parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); + parseContext.profileRequires((yyvsp[-2].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); + if (parseContext.profile == EEsProfile) + parseContext.arraySizeRequiredCheck((yyvsp[-2].interm.type).loc, *(yyvsp[-2].interm.type).arraySizes); + } + + (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); + + parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); + parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); + parseContext.mergeQualifiers((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, (yyvsp[-3].interm.type).qualifier, true); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + + for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { + parseContext.arrayDimCheck((yyvsp[-3].interm.type).loc, (*(yyval.interm.typeList))[i].type, (yyvsp[-2].interm.type).arraySizes); + (*(yyval.interm.typeList))[i].type->mergeType((yyvsp[-2].interm.type)); + } + } +#line 5906 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 302: +#line 2002 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.typeList) = new TTypeList; + (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); + } +#line 5915 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 303: +#line 2006 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); + } +#line 5923 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 304: +#line 2012 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.typeLine).type = new TType(EbtVoid); + (yyval.interm.typeLine).loc = (yyvsp[0].lex).loc; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[0].lex).string); + } +#line 5933 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 305: +#line 2017 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.arrayDimCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes, 0); + + (yyval.interm.typeLine).type = new TType(EbtVoid); + (yyval.interm.typeLine).loc = (yyvsp[-1].lex).loc; + (yyval.interm.typeLine).type->setFieldName(*(yyvsp[-1].lex).string); + (yyval.interm.typeLine).type->newArraySizes(*(yyvsp[0].interm).arraySizes); + } +#line 5946 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 306: +#line 2028 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 5954 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 307: +#line 2031 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + const char* initFeature = "{ } style initializers"; + parseContext.requireProfile((yyvsp[-2].lex).loc, ~EEsProfile, initFeature); + parseContext.profileRequires((yyvsp[-2].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); + (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); + } +#line 5965 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 308: +#line 2037 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + const char* initFeature = "{ } style initializers"; + parseContext.requireProfile((yyvsp[-3].lex).loc, ~EEsProfile, initFeature); + parseContext.profileRequires((yyvsp[-3].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); + (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); + } +#line 5976 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 309: +#line 2046 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[0].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)->getLoc()); + } +#line 5984 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 310: +#line 2049 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); + } +#line 5992 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 311: +#line 2055 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 5998 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 312: +#line 2059 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6004 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 313: +#line 2060 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6010 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 314: +#line 2066 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6016 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 315: +#line 2067 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6022 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 316: +#line 2068 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6028 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 317: +#line 2069 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6034 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 318: +#line 2070 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6040 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 319: +#line 2071 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6046 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 320: +#line 2072 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6052 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 321: +#line 2076 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = 0; } +#line 6058 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 322: +#line 2077 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + } +#line 6067 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 323: +#line 2081 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + } +#line 6076 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 324: +#line 2085 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-2].interm.intermNode) && (yyvsp[-2].interm.intermNode)->getAsAggregate()) + (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-2].interm.intermNode); + } +#line 6086 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 325: +#line 2093 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6092 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 326: +#line 2094 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } +#line 6098 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 327: +#line 2098 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + ++parseContext.controlFlowNestingLevel; + } +#line 6106 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 328: +#line 2101 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + --parseContext.controlFlowNestingLevel; + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6115 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 329: +#line 2105 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.push(); + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 6125 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 330: +#line 2110 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6136 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 331: +#line 2119 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = 0; + } +#line 6144 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 332: +#line 2122 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[-1].interm.intermNode) && (yyvsp[-1].interm.intermNode)->getAsAggregate()) + (yyvsp[-1].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + (yyval.interm.intermNode) = (yyvsp[-1].interm.intermNode); + } +#line 6154 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 333: +#line 2130 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); + if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || + (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { + parseContext.wrapupSwitchSubsequence(0, (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case + } + } +#line 6167 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 334: +#line 2138 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || + (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { + parseContext.wrapupSwitchSubsequence((yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0, (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case + } else + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); + } +#line 6180 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 335: +#line 2149 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = 0; } +#line 6186 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 336: +#line 2150 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { (yyval.interm.intermNode) = static_cast((yyvsp[-1].interm.intermTypedNode)); } +#line 6192 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 337: +#line 2154 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-2].interm.intermTypedNode)); + (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yyvsp[-4].lex).loc); + } +#line 6201 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 338: +#line 2161 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); + } +#line 6210 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 339: +#line 2165 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); + (yyval.interm.nodePair).node2 = 0; + } +#line 6219 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 340: +#line 2173 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + parseContext.boolCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)); + } +#line 6228 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 341: +#line 2177 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.boolCheck((yyvsp[-2].lex).loc, (yyvsp[-3].interm.type)); + + TType type((yyvsp[-3].interm.type)); + TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); + if (initNode) + (yyval.interm.intermTypedNode) = initNode->getAsTyped(); + else + (yyval.interm.intermTypedNode) = 0; + } +#line 6243 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 342: +#line 2190 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // start new switch sequence on the switch stack + ++parseContext.controlFlowNestingLevel; + ++parseContext.statementNestingLevel; + parseContext.switchSequenceStack.push_back(new TIntermSequence); + parseContext.switchLevel.push_back(parseContext.statementNestingLevel); + parseContext.symbolTable.push(); + } +#line 6256 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 343: +#line 2198 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[-7].lex).loc, (yyvsp[-5].interm.intermTypedNode), (yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0); + delete parseContext.switchSequenceStack.back(); + parseContext.switchSequenceStack.pop_back(); + parseContext.switchLevel.pop_back(); + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 6270 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 344: +#line 2210 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = 0; + } +#line 6278 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 345: +#line 2213 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6286 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 346: +#line 2219 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = 0; + if (parseContext.switchLevel.size() == 0) + parseContext.error((yyvsp[-2].lex).loc, "cannot appear outside switch statement", "case", ""); + else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) + parseContext.error((yyvsp[-2].lex).loc, "cannot be nested inside control flow", "case", ""); + else { + parseContext.constantValueCheck((yyvsp[-1].interm.intermTypedNode), "case"); + parseContext.integerCheck((yyvsp[-1].interm.intermTypedNode), "case"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); + } + } +#line 6303 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 347: +#line 2231 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = 0; + if (parseContext.switchLevel.size() == 0) + parseContext.error((yyvsp[-1].lex).loc, "cannot appear outside switch statement", "default", ""); + else if (parseContext.switchLevel.back() != parseContext.statementNestingLevel) + parseContext.error((yyvsp[-1].lex).loc, "cannot be nested inside control flow", "default", ""); + else + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[-1].lex).loc); + } +#line 6317 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 348: +#line 2243 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if (! parseContext.limits.whileLoops) + parseContext.error((yyvsp[-1].lex).loc, "while loops not available", "limitation", ""); + parseContext.symbolTable.push(); + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 6330 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 349: +#line 2251 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, true, (yyvsp[-5].lex).loc); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 6342 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 350: +#line 2258 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 6352 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 351: +#line 2263 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if (! parseContext.limits.whileLoops) + parseContext.error((yyvsp[-7].lex).loc, "do-while loops not available", "limitation", ""); + + parseContext.boolCheck((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode)); + + (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[-5].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, false, (yyvsp[-4].lex).loc); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 6368 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 352: +#line 2274 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.push(); + ++parseContext.loopNestingLevel; + ++parseContext.statementNestingLevel; + ++parseContext.controlFlowNestingLevel; + } +#line 6379 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 353: +#line 2280 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[-3].interm.intermNode), (yyvsp[-5].lex).loc); + TIntermLoop* forLoop = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), reinterpret_cast((yyvsp[-2].interm.nodePair).node1), reinterpret_cast((yyvsp[-2].interm.nodePair).node2), true, (yyvsp[-6].lex).loc); + if (! parseContext.limits.nonInductiveForLoops) + parseContext.inductiveLoopCheck((yyvsp[-6].lex).loc, (yyvsp[-3].interm.intermNode), forLoop); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyval.interm.intermNode), forLoop, (yyvsp[-6].lex).loc); + (yyval.interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + --parseContext.loopNestingLevel; + --parseContext.statementNestingLevel; + --parseContext.controlFlowNestingLevel; + } +#line 6396 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 354: +#line 2295 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6404 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 355: +#line 2298 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6412 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 356: +#line 2304 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); + } +#line 6420 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 357: +#line 2307 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermTypedNode) = 0; + } +#line 6428 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 358: +#line 2313 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = 0; + } +#line 6437 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 359: +#line 2317 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); + (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); + } +#line 6446 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 360: +#line 2324 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if (parseContext.loopNestingLevel <= 0) + parseContext.error((yyvsp[-1].lex).loc, "continue statement only allowed in loops", "", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[-1].lex).loc); + } +#line 6456 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 361: +#line 2329 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) + parseContext.error((yyvsp[-1].lex).loc, "break statement only allowed in switch and loops", "", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[-1].lex).loc); + } +#line 6466 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 362: +#line 2334 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].lex).loc); + if (parseContext.currentFunctionType->getBasicType() != EbtVoid) + parseContext.error((yyvsp[-1].lex).loc, "non-void function must return a value", "return", ""); + if (parseContext.inMain) + parseContext.postMainReturn = true; + } +#line 6478 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 363: +#line 2341 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.functionReturnsValue = true; + if (parseContext.currentFunctionType->getBasicType() == EbtVoid) { + parseContext.error((yyvsp[-2].lex).loc, "void function cannot return a value", "return", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-2].lex).loc); + } else if (*(parseContext.currentFunctionType) != (yyvsp[-1].interm.intermTypedNode)->getType()) { + TIntermTyped* converted = parseContext.intermediate.addConversion(EOpReturn, *parseContext.currentFunctionType, (yyvsp[-1].interm.intermTypedNode)); + if (converted) { + if (parseContext.version < 420) + parseContext.warn((yyvsp[-2].lex).loc, "type conversion on return values was not explicitly allowed until version 420", "return", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, converted, (yyvsp[-2].lex).loc); + } else { + parseContext.error((yyvsp[-2].lex).loc, "type does not match, or is not convertible to, the function's return type", "return", ""); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); + } + } else + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); + } +#line 6501 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 364: +#line 2359 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "discard"); + (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[-1].lex).loc); + } +#line 6510 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 365: +#line 2368 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + } +#line 6519 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 366: +#line 2372 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); + parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); + } +#line 6528 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 367: +#line 2379 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6536 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 368: +#line 2382 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); + } +#line 6544 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 369: +#line 2388 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + (yyvsp[0].interm).function = parseContext.handleFunctionDeclarator((yyvsp[0].interm).loc, *(yyvsp[0].interm).function, false /* not prototype */); + (yyvsp[0].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[0].interm).loc, *(yyvsp[0].interm).function); + } +#line 6553 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + case 370: +#line 2392 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1646 */ + { + // May be best done as post process phase on intermediate code + if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) + parseContext.error((yyvsp[-2].interm).loc, "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str()); + parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermNode)); + parseContext.intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[-2].interm).function->getType(), (yyvsp[-2].interm).loc); + (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[-2].interm).function->getMangledName().c_str()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + (yyval.interm.intermNode)->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); + (yyval.interm.intermNode)->getAsAggregate()->setDebug(parseContext.contextPragma.debug); + (yyval.interm.intermNode)->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable); + } +#line 6573 "glslang_tab.cpp" /* yacc.c:1646 */ + break; + + +#line 6577 "glslang_tab.cpp" /* yacc.c:1646 */ + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (pParseContext, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (pParseContext, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, pParseContext); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, pParseContext); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (pParseContext, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, pParseContext); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, pParseContext); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 2409 "glslang/glslang/MachineIndependent/glslang.y" /* yacc.c:1906 */ + diff --git a/deps/glslang/glslang_tab.cpp.h b/deps/glslang/glslang_tab.cpp.h new file mode 100644 index 0000000000..f1845d727b --- /dev/null +++ b/deps/glslang/glslang_tab.cpp.h @@ -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 . */ + +/* 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 */ diff --git a/deps/glslang/update_yacc.sh b/deps/glslang/update_yacc.sh new file mode 100755 index 0000000000..50f6298ff2 --- /dev/null +++ b/deps/glslang/update_yacc.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bison --defines=glslang_tab.cpp.h -o glslang_tab.cpp -t glslang/glslang/MachineIndependent/glslang.y diff --git a/dir_list_special.c b/dir_list_special.c index 2d202372d8..e02073d341 100644 --- a/dir_list_special.c +++ b/dir_list_special.c @@ -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; diff --git a/dynamic.c b/dynamic.c index ff41b824f8..5629317eec 100644 --- a/dynamic.c +++ b/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. */ diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c new file mode 100644 index 0000000000..69fca5cb76 --- /dev/null +++ b/gfx/common/vulkan_common.c @@ -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 . + */ + +#include "vulkan_common.h" +#include + +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)); +} + diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h new file mode 100644 index 0000000000..8da0ef8795 --- /dev/null +++ b/gfx/common/vulkan_common.h @@ -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 . + */ + +#ifndef VULKAN_COMMON_H__ +#define VULKAN_COMMON_H__ + +#define VK_PROTOTYPES +#include + +#include +#include +#include +#include +#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 +#include + +#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 + diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 393a4f6aeb..31a65a3898 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -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 = { diff --git a/gfx/drivers/sdl_gfx.c b/gfx/drivers/sdl_gfx.c index 689baf6f64..c572630e17 100644 --- a/gfx/drivers/sdl_gfx.c +++ b/gfx/drivers/sdl_gfx.c @@ -19,6 +19,7 @@ #include #include +#include #include "SDL.h" diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c new file mode 100644 index 0000000000..d21e01c914 --- /dev/null +++ b/gfx/drivers/vulkan.c @@ -0,0 +1,2011 @@ +/* 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 . + */ + +#include "../common/vulkan_common.h" +#include "vulkan_shaders/alpha_blend.vert.inc" +#include "vulkan_shaders/alpha_blend.frag.inc" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../driver.h" +#include "../../record/record_driver.h" +#include "../../performance.h" + +#include "../../libretro.h" +#include "../../general.h" +#include "../../retroarch.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../font_driver.h" +#include "../video_context_driver.h" +#include "../video_common.h" + +static void vulkan_set_viewport(void *data, unsigned viewport_width, + unsigned viewport_height, bool force_full, bool allow_rotate); + +#ifdef HAVE_OVERLAY +static void vulkan_overlay_free(vk_t *vk); +static void vulkan_render_overlay(vk_t *vk); +#endif + +static const gfx_ctx_driver_t *vulkan_get_context(vk_t *vk) +{ + unsigned major = 1; + unsigned minor = 0; + settings_t *settings = config_get_ptr(); + enum gfx_ctx_api api = GFX_CTX_VULKAN_API; + + return gfx_ctx_init_first(vk, settings->video.context_driver, + api, major, minor, false); +} + +static void vulkan_init_render_pass(vk_t *vk) +{ + VkAttachmentDescription attachment = {0}; + VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + VkAttachmentReference color_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + VkSubpassDescription subpass = {0}; + + /* Backbuffer format. */ + attachment.format = vk->context->swapchain_format; + /* Not multisampled. */ + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + /* When starting the frame, we want tiles to be cleared. */ + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + /* When end the frame, we want tiles to be written out. */ + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + /* Don't care about stencil since we're not using it. */ + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + + /* The image layout will be attachment_optimal when we're executing the renderpass. */ + attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + /* We have one subpass. + * This subpass has 1 color attachment. */ + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_ref; + + /* Finally, create the renderpass. */ + rp_info.attachmentCount = 1; + rp_info.pAttachments = &attachment; + rp_info.subpassCount = 1; + rp_info.pSubpasses = &subpass; + + vkCreateRenderPass(vk->context->device, &rp_info, NULL, &vk->render_pass); +} + +static void vulkan_init_framebuffers(vk_t *vk) +{ + unsigned i; + vulkan_init_render_pass(vk); + + for (i = 0; i < vk->num_swapchain_images; i++) + { + VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + VkFramebufferCreateInfo info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + + vk->swapchain[i].backbuffer.image = vk->context->swapchain_images[i]; + + /* Create an image view which we can render into. */ + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = vk->context->swapchain_format; + view.image = vk->swapchain[i].backbuffer.image; + view.subresourceRange.baseMipLevel = 0; + view.subresourceRange.baseArrayLayer = 0; + view.subresourceRange.levelCount = 1; + view.subresourceRange.layerCount = 1; + view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + 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; + + vkCreateImageView(vk->context->device, + &view, NULL, &vk->swapchain[i].backbuffer.view); + + /* Create the framebuffer */ + info.renderPass = vk->render_pass; + info.attachmentCount = 1; + info.pAttachments = &vk->swapchain[i].backbuffer.view; + info.width = vk->context->swapchain_width; + info.height = vk->context->swapchain_height; + info.layers = 1; + + vkCreateFramebuffer(vk->context->device, + &info, NULL, &vk->swapchain[i].backbuffer.framebuffer); + } +} + +static void vulkan_init_pipeline_layout(vk_t *vk) +{ + VkDescriptorSetLayoutCreateInfo set_layout_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + VkPipelineLayoutCreateInfo layout_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + VkDescriptorSetLayoutBinding binding = {0}; + VkPushConstantRange push_range = {0}; + + binding.binding = 0; + binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding.pImmutableSamplers = NULL; + + set_layout_info.bindingCount = 1; + set_layout_info.pBindings = &binding; + + vkCreateDescriptorSetLayout(vk->context->device, &set_layout_info, NULL, &vk->pipelines.set_layout); + + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &vk->pipelines.set_layout; + layout_info.pushConstantRangeCount = 1; + layout_info.pPushConstantRanges = &push_range; + + push_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + push_range.offset = 0; + push_range.size = sizeof(struct vk_draw_uniform); + vkCreatePipelineLayout(vk->context->device, &layout_info, NULL, &vk->pipelines.layout); +} + +static void vulkan_init_pipelines(vk_t *vk) +{ + unsigned i; + VkPipelineInputAssemblyStateCreateInfo input_assembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkPipelineVertexInputStateCreateInfo vertex_input = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + VkPipelineColorBlendAttachmentState blend_attachment = {0}; + VkPipelineColorBlendStateCreateInfo blend = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + VkPipelineViewportStateCreateInfo viewport = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + VkPipelineDepthStencilStateCreateInfo depth_stencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + VkPipelineDynamicStateCreateInfo dynamic = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + + VkPipelineShaderStageCreateInfo shader_stages[2] = { + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, + }; + + VkGraphicsPipelineCreateInfo pipe = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; + VkShaderModuleCreateInfo module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + VkVertexInputAttributeDescription attributes[3] = {{0}}; + VkVertexInputBindingDescription binding = {0}; + + static const VkDynamicState dynamics[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + vulkan_init_pipeline_layout(vk); + + /* Input assembly */ + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + /* VAO state */ + attributes[0].location = 0; + attributes[0].binding = 0; + attributes[0].format = VK_FORMAT_R32G32_SFLOAT; + attributes[0].offset = 0; + attributes[1].location = 1; + attributes[1].binding = 0; + attributes[1].format = VK_FORMAT_R32G32_SFLOAT; + attributes[1].offset = 2 * sizeof(float); + attributes[2].location = 2; + attributes[2].binding = 0; + attributes[2].format = VK_FORMAT_R32G32B32A32_SFLOAT; + attributes[2].offset = 4 * sizeof(float); + + binding.binding = 0; + binding.stride = sizeof(struct vk_vertex); + binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + vertex_input.vertexBindingDescriptionCount = 1; + vertex_input.pVertexBindingDescriptions = &binding; + vertex_input.vertexAttributeDescriptionCount = 3; + vertex_input.pVertexAttributeDescriptions = attributes; + + /* Raster state */ + raster.polygonMode = VK_POLYGON_MODE_FILL; + raster.cullMode = VK_CULL_MODE_NONE; + raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + raster.depthClampEnable = false; + raster.rasterizerDiscardEnable = false; + raster.depthBiasEnable = false; + raster.lineWidth = 1.0f; + + /* Blend state */ + blend_attachment.blendEnable = false; + blend_attachment.colorWriteMask = 0xf; + blend.attachmentCount = 1; + blend.pAttachments = &blend_attachment; + + /* Viewport state */ + viewport.viewportCount = 1; + viewport.scissorCount = 1; + + /* Depth-stencil state */ + depth_stencil.depthTestEnable = false; + depth_stencil.depthWriteEnable = false; + depth_stencil.depthBoundsTestEnable = false; + depth_stencil.stencilTestEnable = false; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + + /* Multisample state */ + multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + /* Dynamic state */ + dynamic.pDynamicStates = dynamics; + dynamic.dynamicStateCount = ARRAY_SIZE(dynamics); + + 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->pipelines.layout; + + /* Alpha-blended pipeline. */ + module_info.codeSize = alpha_blend_vert_spv_len; + module_info.pCode = (const uint32_t*)alpha_blend_vert_spv; + shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_stages[0].pName = "main"; + vkCreateShaderModule(vk->context->device, &module_info, NULL, &shader_stages[0].module); + module_info.codeSize = alpha_blend_frag_spv_len; + module_info.pCode = (const uint32_t*)alpha_blend_frag_spv; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].pName = "main"; + vkCreateShaderModule(vk->context->device, &module_info, NULL, &shader_stages[1].module); + + blend_attachment.blendEnable = true; + blend_attachment.colorWriteMask = 0xf; + blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + + vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache, + 1, &pipe, NULL, &vk->pipelines.alpha_blend); + + /* Build display pipelines. */ + for (i = 0; i < 4; i++) + { + input_assembly.topology = i & 2 ? + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP : + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + blend_attachment.blendEnable = i & 1; + vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache, + 1, &pipe, NULL, &vk->display.pipelines[i]); + } + + vkDestroyShaderModule(vk->context->device, shader_stages[0].module, NULL); + vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL); +} + +static void vulkan_init_command_buffers(vk_t *vk) +{ + /* RESET_COMMAND_BUFFER_BIT allows command buffer to be reset. */ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + { + VkCommandPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + + pool_info.queueFamilyIndex = vk->context->graphics_queue_index; + pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(vk->context->device, &pool_info, NULL, &vk->swapchain[i].cmd_pool); + + info.commandPool = vk->swapchain[i].cmd_pool; + info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + info.commandBufferCount = 1; + vkAllocateCommandBuffers(vk->context->device, &info, &vk->swapchain[i].cmd); + } +} + +static void vulkan_init_samplers(vk_t *vk) +{ + VkSamplerCreateInfo info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + info.magFilter = VK_FILTER_NEAREST; + info.minFilter = VK_FILTER_NEAREST; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.mipLodBias = 0.0f; + info.maxAnisotropy = 1.0f; + info.compareEnable = false; + info.minLod = 0.0f; + info.maxLod = 0.0f; + info.unnormalizedCoordinates = false; + info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + + vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.nearest); + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.linear); +} + +static void vulkan_deinit_samplers(vk_t *vk) +{ + vkDestroySampler(vk->context->device, vk->samplers.nearest, NULL); + vkDestroySampler(vk->context->device, vk->samplers.linear, NULL); +} + +static void vulkan_init_buffers(vk_t *vk) +{ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + { + vk->swapchain[i].vbo = vulkan_buffer_chain_init( + VULKAN_BUFFER_BLOCK_SIZE, 16, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + vk->swapchain[i].ubo = vulkan_buffer_chain_init( + VULKAN_BUFFER_BLOCK_SIZE, + vk->context->gpu_properties.limits.minUniformBufferOffsetAlignment, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + } +} + +static void vulkan_deinit_buffers(vk_t *vk) +{ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + { + vulkan_buffer_chain_free(vk->context->device, &vk->swapchain[i].vbo); + vulkan_buffer_chain_free(vk->context->device, &vk->swapchain[i].ubo); + } +} + +static void vulkan_init_descriptor_pool(vk_t *vk) +{ + unsigned i; + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + static const VkDescriptorPoolSize pool_sizes[1] = { + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + }; + + for (i = 0; i < vk->num_swapchain_images; i++) + { + vk->swapchain[i].descriptor_manager = vulkan_create_descriptor_manager(vk->context->device, + pool_sizes, 1, vk->pipelines.set_layout); + } +} + +static void vulkan_deinit_descriptor_pool(vk_t *vk) +{ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + vulkan_destroy_descriptor_manager(vk->context->device, &vk->swapchain[i].descriptor_manager); +} + +static void vulkan_init_textures(vk_t *vk) +{ + unsigned i; + vulkan_init_samplers(vk); + + if (!vk->hw.enable) + { + for (i = 0; i < vk->num_swapchain_images; i++) + { + vk->swapchain[i].texture = vulkan_create_texture(vk, NULL, + vk->tex_w, vk->tex_h, vk->tex_fmt, NULL, NULL, VULKAN_TEXTURE_STREAMED); + vulkan_map_persistent_texture(vk->context->device, + &vk->swapchain[i].texture); + } + } +} + +static void vulkan_deinit_textures(vk_t *vk) +{ + vulkan_deinit_samplers(vk); + + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + if (vk->swapchain[i].texture.memory != VK_NULL_HANDLE) + vulkan_destroy_texture(vk->context->device, &vk->swapchain[i].texture); +} + +static void vulkan_deinit_command_buffers(vk_t *vk) +{ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + { + if (vk->swapchain[i].cmd) + vkFreeCommandBuffers(vk->context->device, + vk->swapchain[i].cmd_pool, 1, &vk->swapchain[i].cmd); + + vkDestroyCommandPool(vk->context->device, vk->swapchain[i].cmd_pool, NULL); + } +} + +static void vulkan_deinit_pipeline_layout(vk_t *vk) +{ + vkDestroyPipelineLayout(vk->context->device, vk->pipelines.layout, NULL); + vkDestroyDescriptorSetLayout(vk->context->device, vk->pipelines.set_layout, NULL); +} + +static void vulkan_deinit_pipelines(vk_t *vk) +{ + unsigned i; + vulkan_deinit_pipeline_layout(vk); + vkDestroyPipeline(vk->context->device, vk->pipelines.alpha_blend, NULL); + for (i = 0; i < 4; i++) + vkDestroyPipeline(vk->context->device, vk->display.pipelines[i], NULL); +} + +static void vulkan_deinit_framebuffers(vk_t *vk) +{ + unsigned i; + for (i = 0; i < vk->num_swapchain_images; i++) + { + vkDestroyFramebuffer(vk->context->device, + vk->swapchain[i].backbuffer.framebuffer, NULL); + vkDestroyImageView(vk->context->device, + vk->swapchain[i].backbuffer.view, NULL); + } + + vkDestroyRenderPass(vk->context->device, vk->render_pass, NULL); +} + +static bool vulkan_init_default_filter_chain(vk_t *vk) +{ + struct vulkan_filter_chain_create_info info; + + memset(&info, 0, sizeof(info)); + info.device = vk->context->device; + info.memory_properties = &vk->context->memory_properties; + info.pipeline_cache = vk->pipelines.cache; + info.max_input_size.width = vk->tex_w; + info.max_input_size.height = vk->tex_h; + info.swapchain.viewport = vk->vk_vp; + info.swapchain.format = vk->context->swapchain_format; + info.swapchain.render_pass = vk->render_pass; + info.swapchain.num_indices = vk->context->num_swapchain_images; + + vk->filter_chain = vulkan_filter_chain_create_default(&info, vk->video.smooth ? VULKAN_FILTER_CHAIN_LINEAR : VULKAN_FILTER_CHAIN_NEAREST); + if (!vk->filter_chain) + { + RARCH_ERR("Failed to create filter chain.\n"); + return false; + } + + return true; +} + +static bool vulkan_init_filter_chain_preset(vk_t *vk, const char *shader_path) +{ + struct vulkan_filter_chain_create_info info; + bool ret = true; + + memset(&info, 0, sizeof(info)); + info.device = vk->context->device; + info.memory_properties = &vk->context->memory_properties; + info.pipeline_cache = vk->pipelines.cache; + info.max_input_size.width = vk->tex_w; + info.max_input_size.height = vk->tex_h; + info.swapchain.viewport = vk->vk_vp; + info.swapchain.format = vk->context->swapchain_format; + info.swapchain.render_pass = vk->render_pass; + info.swapchain.num_indices = vk->context->num_swapchain_images; + + vk->filter_chain = vulkan_filter_chain_create_from_preset(&info, shader_path, + vk->video.smooth ? + VULKAN_FILTER_CHAIN_LINEAR : VULKAN_FILTER_CHAIN_NEAREST); + + if (!vk->filter_chain) + { + RARCH_ERR("[Vulkan]: Failed to create preset: \"%s\".\n", shader_path); + return false; + } + + return true; +} + +static bool vulkan_init_filter_chain(vk_t *vk) +{ + settings_t *settings = config_get_ptr(); + const char *shader_path = (settings->video.shader_enable && *settings->video.shader_path) ? + settings->video.shader_path : NULL; + + enum rarch_shader_type type = video_shader_parse_type(shader_path, RARCH_SHADER_NONE); + + if (type == RARCH_SHADER_NONE) + { + RARCH_LOG("[Vulkan]: Loading stock shader.\n"); + return vulkan_init_default_filter_chain(vk); + } + + if (type != RARCH_SHADER_SLANG) + { + RARCH_LOG("[Vulkan]: Only SLANG shaders are supported, falling back to stock.\n"); + return vulkan_init_default_filter_chain(vk); + } + + if (!shader_path || !vulkan_init_filter_chain_preset(vk, shader_path)) + vulkan_init_default_filter_chain(vk); + + return true; +} + +static void vulkan_init_resources(vk_t *vk) +{ + vk->num_swapchain_images = vk->context->num_swapchain_images; + vulkan_init_framebuffers(vk); + vulkan_init_pipelines(vk); + vulkan_init_descriptor_pool(vk); + vulkan_init_textures(vk); + vulkan_init_buffers(vk); + vulkan_init_command_buffers(vk); +} + +static void vulkan_init_static_resources(vk_t *vk) +{ + VkCommandPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; + unsigned i; + uint32_t blank[4 * 4]; + + /* Create the pipeline cache. */ + VkPipelineCacheCreateInfo cache = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; + vkCreatePipelineCache(vk->context->device, &cache, NULL, &vk->pipelines.cache); + + pool_info.queueFamilyIndex = vk->context->graphics_queue_index; + vkCreateCommandPool(vk->context->device, &pool_info, NULL, &vk->staging_pool); + + for (i = 0; i < 4 * 4; i++) + blank[i] = -1u; + + vk->display.blank_texture = vulkan_create_texture(vk, NULL, + 4, 4, VK_FORMAT_B8G8R8A8_UNORM, blank, NULL, VULKAN_TEXTURE_STATIC); +} + +static void vulkan_deinit_static_resources(vk_t *vk) +{ + unsigned i; + vkDestroyPipelineCache(vk->context->device, vk->pipelines.cache, NULL); + vulkan_destroy_texture(vk->context->device, &vk->display.blank_texture); + vkDestroyCommandPool(vk->context->device, vk->staging_pool, NULL); + free(vk->hw.cmd); + free(vk->hw.wait_dst_stages); + + for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++) + if (vk->readback.staging[i].memory != VK_NULL_HANDLE) + vulkan_destroy_texture(vk->context->device, &vk->readback.staging[i]); +} + +static void vulkan_deinit_resources(vk_t *vk) +{ + vulkan_deinit_pipelines(vk); + vulkan_deinit_framebuffers(vk); + vulkan_deinit_descriptor_pool(vk); + vulkan_deinit_textures(vk); + vulkan_deinit_buffers(vk); + vulkan_deinit_command_buffers(vk); +} + +static void vulkan_deinit_menu(vk_t *vk) +{ + unsigned i; + for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++) + if (vk->menu.textures[i].memory) + vulkan_destroy_texture(vk->context->device, &vk->menu.textures[i]); +} + +static void vulkan_free(void *data) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + if (vk->context && vk->context->device) + { + vkQueueWaitIdle(vk->context->queue); + vulkan_deinit_resources(vk); + + /* No need to init this since textures are create on-demand. */ + vulkan_deinit_menu(vk); + font_driver_free(NULL); + + vulkan_deinit_static_resources(vk); + vulkan_overlay_free(vk); + + if (vk->filter_chain) + vulkan_filter_chain_free(vk->filter_chain); + + gfx_ctx_ctl(GFX_CTL_FREE, NULL); + } + + scaler_ctx_gen_reset(&vk->readback.scaler); + free(vk); +} + +static uint32_t vulkan_get_sync_index(void *handle) +{ + vk_t *vk = (vk_t*)handle; + return vk->context->current_swapchain_index; +} + +static uint32_t vulkan_get_sync_index_mask(void *handle) +{ + vk_t *vk = (vk_t*)handle; + return (1 << vk->context->num_swapchain_images) - 1; +} + +static void vulkan_set_image(void *handle, + const struct retro_vulkan_image *image, + uint32_t num_semaphores, + const VkSemaphore *semaphores) +{ + vk_t *vk = (vk_t*)handle; + unsigned i; + + vk->hw.image = image; + vk->hw.num_semaphores = num_semaphores; + vk->hw.semaphores = semaphores; + + if (num_semaphores > 0) + { + vk->hw.wait_dst_stages = (VkPipelineStageFlags*)realloc(vk->hw.wait_dst_stages, + sizeof(VkPipelineStageFlags) * vk->hw.num_semaphores); + retro_assert(vk->hw.wait_dst_stages); /* If this fails, we're screwed anyways. */ + + for (i = 0; i < vk->hw.num_semaphores; i++) + vk->hw.wait_dst_stages[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } +} + +static void vulkan_wait_sync_index(void *handle) +{ + (void)handle; + /* no-op. RetroArch already waits for this + * in gfx_ctx_swap_buffers(). */ +} + +static void vulkan_set_command_buffers(void *handle, uint32_t num_cmd, + const VkCommandBuffer *cmd) +{ + vk_t *vk = (vk_t*)handle; + unsigned required_capacity = num_cmd + 1; + if (required_capacity > vk->hw.capacity_cmd) + { + vk->hw.cmd = (VkCommandBuffer*)realloc(vk->hw.cmd, + sizeof(VkCommandBuffer) * required_capacity); + retro_assert(vk->hw.cmd); /* If this fails, we're just screwed. */ + vk->hw.capacity_cmd = required_capacity; + } + + vk->hw.num_cmd = num_cmd; + memcpy(vk->hw.cmd, cmd, sizeof(VkCommandBuffer) * num_cmd); +} + +static void vulkan_lock_queue(void *handle) +{ + vk_t *vk = (vk_t*)handle; + slock_lock(vk->context->queue_lock); +} + +static void vulkan_unlock_queue(void *handle) +{ + vk_t *vk = (vk_t*)handle; + slock_unlock(vk->context->queue_lock); +} + +static void vulkan_init_hw_render(vk_t *vk) +{ + const struct retro_hw_render_callback *hw_render = + video_driver_callback(); + struct retro_hw_render_interface_vulkan *iface = + &vk->hw.iface; + + if (hw_render->context_type != RETRO_HW_CONTEXT_VULKAN) + return; + + vk->hw.enable = true; + + iface->interface_type = RETRO_HW_RENDER_INTERFACE_VULKAN; + iface->interface_version = RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION; + iface->instance = vk->context->instance; + iface->gpu = vk->context->gpu; + iface->device = vk->context->device; + + iface->queue = vk->context->queue; + iface->queue_index = vk->context->graphics_queue_index; + + iface->handle = vk; + iface->set_image = vulkan_set_image; + iface->get_sync_index = vulkan_get_sync_index; + iface->get_sync_index_mask = vulkan_get_sync_index_mask; + iface->wait_sync_index = vulkan_wait_sync_index; + iface->set_command_buffers = vulkan_set_command_buffers; + iface->lock_queue = vulkan_lock_queue; + iface->unlock_queue = vulkan_unlock_queue; +} + +static void vulkan_init_readback(vk_t *vk) +{ + /* Only bother with this if we're doing GPU recording. + * Check recording_is_enabled() and not + * driver.recording_data, because recording is + * not initialized yet. + */ + settings_t *settings = config_get_ptr(); + bool *recording_enabled = recording_is_enabled(); + vk->readback.streamed = settings->video.gpu_record && *recording_enabled; + + if (!vk->readback.streamed) + return; + + vk->readback.scaler.in_width = vk->vp.width; + vk->readback.scaler.in_height = vk->vp.height; + vk->readback.scaler.out_width = vk->vp.width; + vk->readback.scaler.out_height = vk->vp.height; + vk->readback.scaler.in_fmt = SCALER_FMT_ARGB8888; + vk->readback.scaler.out_fmt = SCALER_FMT_BGR24; + vk->readback.scaler.scaler_type = SCALER_TYPE_POINT; + + if (!scaler_ctx_gen_filter(&vk->readback.scaler)) + { + vk->readback.streamed = false; + RARCH_ERR("[Vulkan]: Failed to initialize scaler context.\n"); + } +} + +static void *vulkan_init(const video_info_t *video, const input_driver_t **input, + void **input_data) +{ + unsigned win_width, win_height, temp_width = 0, temp_height = 0; + const gfx_ctx_driver_t *ctx_driver = NULL; + settings_t *settings = config_get_ptr(); + gfx_ctx_mode_t mode; + gfx_ctx_input_t inp; + unsigned interval; + + vk_t *vk = (vk_t*)calloc(1, sizeof(*vk)); + if (!vk) + return NULL; + + vk->video = *video; + + ctx_driver = vulkan_get_context(vk); + if (!ctx_driver) + goto error; + + gfx_ctx_ctl(GFX_CTL_SET, (void*)ctx_driver); + + gfx_ctx_ctl(GFX_CTL_GET_VIDEO_SIZE, &mode); + vk->full_x = mode.width; + vk->full_y = mode.height; + + RARCH_LOG("Detecting screen resolution %ux%u.\n", vk->full_x, vk->full_y); + interval = video->vsync ? settings->video.swap_interval : 0; + gfx_ctx_ctl(GFX_CTL_SWAP_INTERVAL, &interval); + + win_width = video->width; + win_height = video->height; + + if (video->fullscreen && (win_width == 0) && (win_height == 0)) + { + win_width = vk->full_x; + win_height = vk->full_y; + } + + mode.fullscreen = video->fullscreen; + if (!gfx_ctx_ctl(GFX_CTL_SET_VIDEO_MODE, &mode)) + goto error; + + gfx_ctx_ctl(GFX_CTL_GET_VIDEO_SIZE, &mode); + temp_width = mode.width; + temp_height = mode.height; + + if (temp_width != 0 && temp_height != 0) + video_driver_set_size(&temp_width, &temp_height); + video_driver_get_size(&temp_width, &temp_height); + + RARCH_LOG("Vulkan: Using resolution %ux%u\n", temp_width, temp_height); + + /* FIXME: Is this check right? */ + if (vk->full_x || vk->full_y) + { + /* We got bogus from gfx_ctx_get_video_size. Replace. */ + vk->full_x = temp_width; + vk->full_y = temp_height; + } + + /* Set the viewport to fix recording, since it needs to know + * the viewport sizes before we start running. */ + vulkan_set_viewport(vk, temp_width, temp_height, false, true); + + gfx_ctx_ctl(GFX_CTL_GET_CONTEXT_DATA, &vk->context); + + vk->vsync = video->vsync; + vk->fullscreen = video->fullscreen; + vk->tex_w = vk->tex_h = RARCH_SCALE_BASE * video->input_scale; + vk->tex_fmt = video->rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R5G6B5_UNORM_PACK16; + vk->keep_aspect = video->force_aspect; + + vulkan_init_hw_render(vk); + vulkan_init_static_resources(vk); + vulkan_init_resources(vk); + + if (!vulkan_init_filter_chain(vk)) + goto error; + + inp.input = input; + inp.input_data = input_data; + gfx_ctx_ctl(GFX_CTL_INPUT_DRIVER, &inp); + + if (settings->video.font_enable) + { + if (!font_driver_init_first(NULL, NULL, vk, *settings->video.font_path + ? settings->video.font_path : NULL, settings->video.font_size, false, + FONT_DRIVER_RENDER_VULKAN_API)) + RARCH_ERR("[Vulkan]: Failed to initialize font renderer.\n"); + } + + vulkan_init_readback(vk); + return vk; + +error: + vulkan_free(vk); + return NULL; +} + +static void vulkan_update_filter_chain(vk_t *vk) +{ + const struct vulkan_filter_chain_swapchain_info info = { + vk->vk_vp, + vk->context->swapchain_format, + vk->render_pass, + vk->context->num_swapchain_images, + }; + + if (!vulkan_filter_chain_update_swapchain_info(vk->filter_chain, &info)) + RARCH_ERR("Failed to update filter chain info. This will probably lead to a crash ...\n"); +} + +static void vulkan_check_swapchain(vk_t *vk) +{ + if (vk->context->invalid_swapchain) + { + vkQueueWaitIdle(vk->context->queue); + + vulkan_deinit_resources(vk); + vulkan_init_resources(vk); + vk->context->invalid_swapchain = false; + + vulkan_update_filter_chain(vk); + } +} + +static void vulkan_set_nonblock_state(void *data, bool state) +{ + vk_t *vk = (vk_t*)data; + settings_t *settings = config_get_ptr(); + unsigned interval; + + if (!vk) + return; + + RARCH_LOG("[Vulkan]: VSync => %s\n", state ? "off" : "on"); + + interval = state ? 0 : settings->video.swap_interval; + gfx_ctx_ctl(GFX_CTL_SWAP_INTERVAL, &interval); + + /* Changing vsync might require recreating the swapchain, which means new VkImages + * to render into. */ + vulkan_check_swapchain(vk); +} + +static bool vulkan_alive(void *data) +{ + gfx_ctx_size_t size_data; + unsigned temp_width = 0, temp_height = 0; + bool ret = false; + bool quit = false, resize = false; + vk_t *vk = (vk_t*)data; + + video_driver_get_size(&temp_width, &temp_height); + + size_data.quit = &quit; + size_data.resize = &resize; + size_data.width = &temp_width; + size_data.height = &temp_height; + + if (gfx_ctx_ctl(GFX_CTL_CHECK_WINDOW, &size_data)) + { + if (quit) + vk->quitting = true; + else if (resize) + vk->should_resize = true; + + ret = !vk->quitting; + } + + if (temp_width != 0 && temp_height != 0) + video_driver_set_size(&temp_width, &temp_height); + + return ret; +} + +static bool vulkan_focus(void *data) +{ + (void)data; + return gfx_ctx_ctl(GFX_CTL_FOCUS, NULL); +} + +static bool vulkan_suppress_screensaver(void *data, bool enable) +{ + (void)data; + bool enabled = enable; + return gfx_ctx_ctl(GFX_CTL_SUPPRESS_SCREENSAVER, &enabled); +} + +static bool vulkan_has_windowed(void *data) +{ + (void)data; + return gfx_ctx_ctl(GFX_CTL_HAS_WINDOWED, NULL); +} + +static bool vulkan_set_shader(void *data, enum rarch_shader_type type, const char *path) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return false; + + if (type != RARCH_SHADER_SLANG && path) + { + RARCH_WARN("[Vulkan]: Only .slang or .slangp shaders are supported. Falling back to stock.\n"); + path = NULL; + } + + if (vk->filter_chain) + vulkan_filter_chain_free(vk->filter_chain); + vk->filter_chain = NULL; + + if (!path) + { + vulkan_init_default_filter_chain(vk); + return true; + } + + if (!vulkan_init_filter_chain_preset(vk, path)) + { + RARCH_ERR("[Vulkan]: Failed to create filter chain: \"%s\". Falling back to stock.\n", path); + vulkan_init_default_filter_chain(vk); + return false; + } + + return true; +} + +static void vulkan_set_projection(vk_t *vk, struct gfx_ortho *ortho, bool allow_rotate) +{ + math_matrix_4x4 rot; + + /* Calculate projection. */ + matrix_4x4_ortho(&vk->mvp_no_rot, ortho->left, ortho->right, + ortho->bottom, ortho->top, ortho->znear, ortho->zfar); + + if (!allow_rotate) + { + vk->mvp = vk->mvp_no_rot; + return; + } + + matrix_4x4_rotate_z(&rot, M_PI * vk->rotation / 180.0f); + matrix_4x4_multiply(&vk->mvp, &rot, &vk->mvp_no_rot); +} + +static void vulkan_set_rotation(void *data, unsigned rotation) +{ + vk_t *vk = (vk_t*)data; + struct gfx_ortho ortho = {0, 1, 0, 1, -1, 1}; + + if (!vk) + return; + + vk->rotation = 90 * rotation; + vulkan_set_projection(vk, &ortho, true); +} + +static void vulkan_set_video_mode(void *data, unsigned width, unsigned height, + bool fullscreen) +{ + (void)data; + gfx_ctx_mode_t mode; + + mode.width = width; + mode.height = height; + mode.fullscreen = fullscreen; + + gfx_ctx_ctl(GFX_CTL_SET_VIDEO_MODE, &mode); +} + +static void vulkan_set_viewport(void *data, unsigned viewport_width, + unsigned viewport_height, bool force_full, bool allow_rotate) +{ + gfx_ctx_aspect_t aspect_data; + unsigned width, height; + int x = 0, y = 0; + float device_aspect = (float)viewport_width / viewport_height; + struct gfx_ortho ortho = {0, 1, 0, 1, -1, 1}; + settings_t *settings = config_get_ptr(); + vk_t *vk = (vk_t*)data; + + video_driver_get_size(&width, &height); + + aspect_data.aspect = &device_aspect; + aspect_data.width = viewport_width; + aspect_data.height = viewport_height; + + gfx_ctx_ctl(GFX_CTL_TRANSLATE_ASPECT, &aspect_data); + + if (settings->video.scale_integer && !force_full) + { + video_viewport_get_scaled_integer(&vk->vp, + viewport_width, viewport_height, + video_driver_get_aspect_ratio(), vk->keep_aspect); + viewport_width = vk->vp.width; + viewport_height = vk->vp.height; + } + else if (vk->keep_aspect && !force_full) + { + float desired_aspect = video_driver_get_aspect_ratio(); + +#if defined(HAVE_MENU) + if (settings->video.aspect_ratio_idx == ASPECT_RATIO_CUSTOM) + { + const struct video_viewport *custom = video_viewport_get_custom(); + + /* Vukan has top-left origin viewport. */ + x = custom->x; + y = custom->y; + viewport_width = custom->width; + viewport_height = custom->height; + } + else +#endif + { + float delta; + + if (fabsf(device_aspect - desired_aspect) < 0.0001f) + { + /* If the aspect ratios of screen and desired aspect + * ratio are sufficiently equal (floating point stuff), + * assume they are actually equal. + */ + } + else if (device_aspect > desired_aspect) + { + delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f; + x = (int)roundf(viewport_width * (0.5f - delta)); + viewport_width = (unsigned)roundf(2.0f * viewport_width * delta); + } + else + { + delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f; + y = (int)roundf(viewport_height * (0.5f - delta)); + viewport_height = (unsigned)roundf(2.0f * viewport_height * delta); + } + } + + vk->vp.x = x; + vk->vp.y = y; + vk->vp.width = viewport_width; + vk->vp.height = viewport_height; + } + else + { + vk->vp.x = vk->vp.y = 0; + vk->vp.width = viewport_width; + vk->vp.height = viewport_height; + } + +#if defined(RARCH_MOBILE) + /* In portrait mode, we want viewport to gravitate to top of screen. */ + if (device_aspect < 1.0f) + vk->vp.y = 0; +#endif + + vulkan_set_projection(vk, &ortho, allow_rotate); + + /* Set last backbuffer viewport. */ + if (!force_full) + { + vk->vp_out_width = viewport_width; + vk->vp_out_height = viewport_height; + } + + vk->vk_vp.x = (float)vk->vp.x; + vk->vk_vp.y = (float)vk->vp.y; + vk->vk_vp.width = (float)vk->vp.width; + vk->vk_vp.height = (float)vk->vp.height; + vk->vk_vp.minDepth = 0.0f; + vk->vk_vp.maxDepth = 1.0f; + + vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT; + +#if 0 + RARCH_LOG("Setting viewport @ %ux%u\n", viewport_width, viewport_height); +#endif +} + +static void vulkan_readback(vk_t *vk) +{ + VkImageBlit blit; + struct vk_texture *staging; + + /* FIXME: Is this inclusive or exclusive range? */ + memset(&blit, 0, sizeof(blit)); + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.layerCount = 1; + blit.dstSubresource = blit.srcSubresource; + blit.srcOffsets[0].x = vk->vp.x; + blit.srcOffsets[0].y = vk->vp.y; + blit.srcOffsets[0].z = 0; + blit.srcOffsets[1].x = vk->vp.x + vk->vp.width; + blit.srcOffsets[1].y = vk->vp.y + vk->vp.height; + blit.srcOffsets[1].z = 1; + blit.dstOffsets[0].x = 0; + blit.dstOffsets[0].y = 0; + blit.dstOffsets[0].z = 0; + blit.dstOffsets[1].x = vk->vp.width; + blit.dstOffsets[1].y = vk->vp.height; + blit.dstOffsets[1].z = 1; + + staging = &vk->readback.staging[vk->context->current_swapchain_index]; + *staging = vulkan_create_texture(vk, + staging->memory != VK_NULL_HANDLE ? staging : NULL, + vk->vp.width, vk->vp.height, + vk->context->swapchain_is_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM, + NULL, NULL, VULKAN_TEXTURE_READBACK); + + /* Go through the long-winded dance of remapping image layouts. */ + vulkan_image_layout_transition(vk, vk->cmd, staging->image, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + + vkCmdBlitImage(vk->cmd, + vk->chain->backbuffer.image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + staging->image, + VK_IMAGE_LAYOUT_GENERAL, + 1, &blit, + VK_FILTER_NEAREST); + + /* Make the data visible to host. */ + vulkan_image_layout_transition(vk, vk->cmd, staging->image, + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_HOST_BIT); +} + +static bool vulkan_frame(void *data, const void *frame, + unsigned frame_width, unsigned frame_height, + uint64_t frame_count, + unsigned pitch, const char *msg) +{ + vk_t *vk = (vk_t*)data; + settings_t *settings = config_get_ptr(); + static struct retro_perf_counter frame_run = {0}; + static struct retro_perf_counter copy_frame = {0}; + static struct retro_perf_counter swapbuffers = {0}; + static struct retro_perf_counter queue_submit = {0}; + struct vk_per_frame *chain; + unsigned width, height; + VkClearValue clear_value; + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; + VkRenderPassBeginInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + unsigned frame_index = vk->context->current_swapchain_index; + + rarch_perf_init(&frame_run, "frame_run"); + rarch_perf_init(©_frame, "copy_frame"); + rarch_perf_init(&swapbuffers, "swapbuffers"); + rarch_perf_init(&queue_submit, "queue_submit"); + retro_perf_start(&frame_run); + + video_driver_get_size(&width, &height); + + /* Bookkeeping on start of frame. */ + chain = &vk->swapchain[frame_index]; + vk->chain = chain; + + vulkan_descriptor_manager_restart(&chain->descriptor_manager); + vulkan_buffer_chain_discard(&chain->vbo); + vulkan_buffer_chain_discard(&chain->ubo); + + /* Upload texture */ + retro_perf_start(©_frame); + if (frame && !vk->hw.enable) + { + unsigned y; + uint8_t *dst = NULL; + const uint8_t *src = (const uint8_t*)frame; + unsigned bpp = vk->video.rgb32 ? 4 : 2; + + if (chain->texture.width != frame_width || chain->texture.height != frame_height) + { + chain->texture = vulkan_create_texture(vk, &chain->texture, + frame_width, frame_height, chain->texture.format, NULL, NULL, VULKAN_TEXTURE_STREAMED); + vulkan_map_persistent_texture(vk->context->device, &chain->texture); + } + + if (frame != chain->texture.mapped) + { + dst = (uint8_t*)chain->texture.mapped; + if (chain->texture.stride == pitch && pitch == frame_width * bpp) + memcpy(dst, src, frame_width * frame_height * bpp); + else + for (y = 0; y < frame_height; y++, dst += chain->texture.stride, src += pitch) + memcpy(dst, src, frame_width * bpp); + } + + vk->last_valid_index = frame_index; + } + retro_perf_stop(©_frame); + + /* Start recording the command buffer. */ + vk->cmd = chain->cmd; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkResetCommandBuffer(vk->cmd, 0); + vkBeginCommandBuffer(vk->cmd, &begin_info); + memset(&vk->tracker, 0, sizeof(vk->tracker)); + + /* Notify filter chain about the new sync index. */ + vulkan_filter_chain_notify_sync_index(vk->filter_chain, frame_index); + + /* Render offscreen filter chain passes. */ + { + /* Set the source texture in the filter chain */ + struct vulkan_filter_chain_texture input; + + if (vk->hw.enable) + { + /* Does this make that this can happen at all? */ + if (!vk->hw.image) + { + RARCH_ERR("[Vulkan]: HW image is not set. Buggy core?\n"); + return false; + } + + input.view = vk->hw.image->image_view; + input.layout = vk->hw.image->image_layout; + + if (frame) + { + input.width = frame_width; + input.height = frame_height; + } + else + { + input.width = vk->hw.last_width; + input.height = vk->hw.last_height; + } + + vk->hw.last_width = input.width; + vk->hw.last_height = input.height; + } + else + { + struct vk_texture *tex = &vk->swapchain[vk->last_valid_index].texture; + vulkan_transition_texture(vk, tex); + + input.view = tex->view; + input.layout = tex->layout; + input.width = tex->width; + input.height = tex->height; + } + + vulkan_filter_chain_set_input_texture(vk->filter_chain, &input); + } + + vulkan_set_viewport(vk, width, height, false, true); + + vulkan_filter_chain_build_offscreen_passes(vk->filter_chain, vk->cmd, &vk->vk_vp); + + /* Render to backbuffer. */ + clear_value.color.float32[0] = 0.0f; + clear_value.color.float32[1] = 0.0f; + clear_value.color.float32[2] = 0.0f; + clear_value.color.float32[3] = 1.0f; + rp_info.renderPass = vk->render_pass; + rp_info.framebuffer = chain->backbuffer.framebuffer; + rp_info.renderArea.extent.width = vk->context->swapchain_width; + rp_info.renderArea.extent.height = vk->context->swapchain_height; + rp_info.clearValueCount = 1; + rp_info.pClearValues = &clear_value; + + /* Prepare backbuffer for rendering */ + vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + + /* Begin render pass and set up viewport */ + vkCmdBeginRenderPass(vk->cmd, &rp_info, VK_SUBPASS_CONTENTS_INLINE); + + vulkan_filter_chain_build_viewport_pass(vk->filter_chain, vk->cmd, + &vk->vk_vp, vk->mvp.data); + +#if defined(HAVE_MENU) + if (vk->menu.enable) + { + menu_driver_ctl(RARCH_MENU_CTL_FRAME, NULL); + + if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE) + { + struct vk_draw_quad quad; + vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false); + + quad.pipeline = vk->pipelines.alpha_blend; + quad.texture = &vk->menu.textures[vk->menu.last_index]; + quad.sampler = vk->samplers.linear; + quad.mvp = &vk->mvp_no_rot; + quad.color.r = 1.0f; + quad.color.g = 1.0f; + quad.color.b = 1.0f; + quad.color.a = vk->menu.alpha; + vulkan_draw_quad(vk, &quad); + } + } +#endif + + if (msg) + font_driver_render_msg(NULL, msg, NULL); + +#ifdef HAVE_OVERLAY + if (vk->overlay.enable) + vulkan_render_overlay(vk); +#endif + + /* End the render pass. We're done rendering to backbuffer now. */ + vkCmdEndRenderPass(vk->cmd); + + if (vk->readback.pending || vk->readback.streamed) + { + /* We cannot safely read back from an image which has already been presented + * as we need to maintain the PRESENT_SRC_KHR layout. + * If we're reading back, perform the readback before presenting. + */ + vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + vulkan_readback(vk); + + /* Prepare for presentation after transfers are complete. */ + vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + + vk->readback.pending = false; + } + else + { + /* Prepare backbuffer for presentation. */ + vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + } + + vkEndCommandBuffer(vk->cmd); + + /* Submit command buffers to GPU. */ + + if (vk->hw.num_cmd) + { + /* vk->hw.cmd has already been allocated for this. */ + vk->hw.cmd[vk->hw.num_cmd] = vk->cmd; + + submit_info.commandBufferCount = vk->hw.num_cmd + 1; + submit_info.pCommandBuffers = vk->hw.cmd; + + vk->hw.num_cmd = 0; + } + else + { + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &vk->cmd; + } + + if (vk->hw.enable && frame && !vk->hw.num_cmd) + { + submit_info.waitSemaphoreCount = vk->hw.num_semaphores; + submit_info.pWaitSemaphores = vk->hw.semaphores; + submit_info.pWaitDstStageMask = vk->hw.wait_dst_stages; + } + + submit_info.signalSemaphoreCount = vk->context->swapchain_semaphores[frame_index] != VK_NULL_HANDLE ? 1 : 0; + submit_info.pSignalSemaphores = &vk->context->swapchain_semaphores[frame_index]; + retro_perf_stop(&frame_run); + + retro_perf_start(&queue_submit); + + slock_lock(vk->context->queue_lock); + vkQueueSubmit(vk->context->queue, 1, &submit_info, vk->context->swapchain_fences[frame_index]); + slock_unlock(vk->context->queue_lock); + retro_perf_stop(&queue_submit); + + retro_perf_start(&swapbuffers); + gfx_ctx_ctl(GFX_CTL_SWAP_BUFFERS, NULL); + retro_perf_stop(&swapbuffers); + + gfx_ctx_ctl(GFX_CTL_UPDATE_WINDOW_TITLE, NULL); + + /* Handle spurious swapchain invalidations as soon as we can, + * i.e. right after swap buffers. */ + if (vk->should_resize) + { + gfx_ctx_mode_t mode; + mode.width = width; + mode.height = height; + gfx_ctx_ctl(GFX_CTL_SET_RESIZE, &mode); + + vk->should_resize = false; + } + vulkan_check_swapchain(vk); + + return true; +} + +static void vulkan_set_aspect_ratio(void *data, unsigned aspect_ratio_idx) +{ + vk_t *vk = (vk_t*)data; + enum rarch_display_ctl_state cmd = RARCH_DISPLAY_CTL_NONE; + + switch (aspect_ratio_idx) + { + case ASPECT_RATIO_SQUARE: + cmd = RARCH_DISPLAY_CTL_SET_VIEWPORT_SQUARE_PIXEL; + break; + + case ASPECT_RATIO_CORE: + cmd = RARCH_DISPLAY_CTL_SET_VIEWPORT_CORE; + break; + + case ASPECT_RATIO_CONFIG: + cmd = RARCH_DISPLAY_CTL_SET_VIEWPORT_CONFIG; + break; + + default: + break; + } + + if (cmd != RARCH_DISPLAY_CTL_NONE) + video_driver_ctl(cmd, NULL); + + video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value); + + if (!vk) + return; + + vk->keep_aspect = true; + vk->should_resize = true; +} + +static void vulkan_apply_state_changes(void *data) +{ + vk_t *vk = (vk_t*)data; + if (vk) + vk->should_resize = true; +} + +static void vulkan_show_mouse(void *data, bool state) +{ + (void)data; + gfx_ctx_ctl(GFX_CTL_SHOW_MOUSE, &state); +} + +static struct video_shader *vulkan_get_current_shader(void *data) +{ + vk_t *vk = (vk_t*)data; + if (!vk || !vk->filter_chain) + return NULL; + + return vulkan_filter_chain_get_preset(vk->filter_chain); +} + +static bool vulkan_get_current_sw_framebuffer(void *data, struct retro_framebuffer *framebuffer) +{ + vk_t *vk = (vk_t*)data; + struct vk_per_frame *chain; + vk->chain = &vk->swapchain[vk->context->current_swapchain_index]; + chain = vk->chain; + + if (chain->texture.width != framebuffer->width || + chain->texture.height != framebuffer->height) + { + chain->texture = vulkan_create_texture(vk, &chain->texture, + framebuffer->width, framebuffer->height, chain->texture.format, + NULL, NULL, VULKAN_TEXTURE_STREAMED); + vulkan_map_persistent_texture(vk->context->device, &chain->texture); + } + + framebuffer->data = chain->texture.mapped; + framebuffer->pitch = chain->texture.stride; + framebuffer->format = vk->video.rgb32 ? RETRO_PIXEL_FORMAT_XRGB8888 : RETRO_PIXEL_FORMAT_RGB565; + + framebuffer->memory_flags = 0; + if (vk->context->memory_properties.memoryTypes[chain->texture.memory_type].propertyFlags & + VK_MEMORY_PROPERTY_HOST_CACHED_BIT) + { + framebuffer->memory_flags |= RETRO_MEMORY_TYPE_CACHED; + } + + return true; +} + +static bool vulkan_get_hw_render_interface(void *data, const struct retro_hw_render_interface **iface) +{ + vk_t *vk = (vk_t*)data; + *iface = (const struct retro_hw_render_interface*)&vk->hw.iface; + return vk->hw.enable; +} + +#if defined(HAVE_MENU) +static void vulkan_set_texture_frame(void *data, + const void *frame, bool rgb32, unsigned width, unsigned height, + float alpha) +{ + vk_t *vk = (vk_t*)data; + unsigned index = vk->context->current_swapchain_index; + struct vk_texture *texture = &vk->menu.textures[index]; + uint8_t *ptr; + unsigned x, y; + const VkComponentMapping br_swizzle = { + VK_COMPONENT_SWIZZLE_B, + VK_COMPONENT_SWIZZLE_G, + VK_COMPONENT_SWIZZLE_R, + VK_COMPONENT_SWIZZLE_A, + }; + + if (!vk) + return; + + /* B4G4R4A4 must be supported, but R4G4B4A4 is optional, + * just apply the swizzle in the image view instead. */ + *texture = vulkan_create_texture(vk, + texture->memory ? texture : NULL, + width, height, + rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16, + NULL, rgb32 ? NULL : &br_swizzle, VULKAN_TEXTURE_STREAMED); + + vkMapMemory(vk->context->device, texture->memory, + texture->offset, texture->size, 0, (void**)&ptr); + + uint8_t *dst = ptr; + const uint8_t *src = (const uint8_t*)frame; + unsigned stride = (rgb32 ? sizeof(uint32_t) : sizeof(uint16_t)) * width; + for (y = 0; y < height; y++, dst += texture->stride, src += stride) + memcpy(dst, src, stride); + + vkUnmapMemory(vk->context->device, texture->memory); + vk->menu.alpha = alpha; + vk->menu.last_index = index; +} + +static void vulkan_set_texture_enable(void *data, bool state, bool full_screen) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + vk->menu.enable = state; + vk->menu.full_screen = full_screen; +} + +static void vulkan_set_osd_msg(void *data, const char *msg, + const struct font_params *params, void *font) +{ + (void)data; + font_driver_render_msg(font, msg, params); +} +#endif + +static uintptr_t vulkan_load_texture(void *video_data, void *data, + bool threaded, enum texture_filter_type filter_type) +{ + vk_t *vk = (vk_t*)video_data; + struct texture_image *image = (struct texture_image*)data; + (void)threaded; /* Pfft. */ + + struct vk_texture *texture = (struct vk_texture*)calloc(1, sizeof(*texture)); + if (!texture) + return 0; + + *texture = vulkan_create_texture(vk, NULL, + image->width, image->height, VK_FORMAT_B8G8R8A8_UNORM, + image->pixels, NULL, VULKAN_TEXTURE_STATIC); + + /* TODO: Actually add mipmapping support. + * Optimal tiling would make sense here as well ... */ + texture->default_smooth = + filter_type == TEXTURE_FILTER_MIPMAP_LINEAR || filter_type == TEXTURE_FILTER_LINEAR; + + return (uintptr_t)texture; +} + +static void vulkan_unload_texture(void *data, uintptr_t handle) +{ + vk_t *vk = (vk_t*)data; + struct vk_texture *texture = (struct vk_texture*)handle; + if (!texture) + return; + + /* TODO: We really want to defer this deletion instead, + * but this will do for now. */ + vkQueueWaitIdle(vk->context->queue); + vulkan_destroy_texture(vk->context->device, texture); + free(texture); +} + +static const video_poke_interface_t vulkan_poke_interface = { + vulkan_load_texture, + vulkan_unload_texture, + vulkan_set_video_mode, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + vulkan_set_aspect_ratio, + vulkan_apply_state_changes, +#if defined(HAVE_MENU) + vulkan_set_texture_frame, + vulkan_set_texture_enable, +#else + NULL, + NULL, +#endif + vulkan_set_osd_msg, + vulkan_show_mouse, + NULL, + vulkan_get_current_shader, + vulkan_get_current_sw_framebuffer, + vulkan_get_hw_render_interface, +}; + +static void vulkan_get_poke_interface(void *data, + const video_poke_interface_t **iface) +{ + (void)data; + *iface = &vulkan_poke_interface; +} + +static void vulkan_viewport_info(void *data, struct video_viewport *vp) +{ + vk_t *vk = (vk_t*)data; + unsigned width, height; + + video_driver_get_size(&width, &height); + *vp = vk->vp; + vp->full_width = width; + vp->full_height = height; +} + +static bool vulkan_read_viewport(void *data, uint8_t *buffer) +{ + vk_t *vk = (vk_t*)data; + struct vk_texture *staging; + + if (!vk) + return false; + + staging = &vk->readback.staging[vk->context->current_swapchain_index]; + + if (vk->readback.streamed) + { + if (staging->memory == VK_NULL_HANDLE) + return false; + + const uint8_t *src; + unsigned x, y; + + buffer += 3 * (vk->vp.height - 1) * vk->vp.width; + vkMapMemory(vk->context->device, staging->memory, + staging->offset, staging->size, 0, (void**)&src); + + vk->readback.scaler.in_stride = staging->stride; + vk->readback.scaler.out_stride = -(int)vk->vp.width * 3; + scaler_ctx_scale(&vk->readback.scaler, buffer, src); + + vkUnmapMemory(vk->context->device, staging->memory); + } + else + { + /* Synchronous path only for now. */ + /* TODO: How will we deal with format conversion? + * For now, take the simplest route and use image blitting + * with conversion. */ + + vk->readback.pending = true; + video_driver_ctl(RARCH_DISPLAY_CTL_CACHED_FRAME_RENDER, NULL); + vkQueueWaitIdle(vk->context->queue); + + if (!staging->mapped) + vulkan_map_persistent_texture(vk->context->device, staging); + + { + unsigned x, y; + const uint8_t *src = (const uint8_t*)staging->mapped; + buffer += 3 * (vk->vp.height - 1) * vk->vp.width; + + for (y = 0; y < vk->vp.height; y++, + src += staging->stride, buffer -= 3 * vk->vp.width) + { + for (x = 0; x < vk->vp.width; x++) + { + buffer[3 * x + 0] = src[4 * x + 0]; + buffer[3 * x + 1] = src[4 * x + 1]; + buffer[3 * x + 2] = src[4 * x + 2]; + } + } + } + vulkan_destroy_texture(vk->context->device, staging); + } + return true; +} + +#ifdef HAVE_OVERLAY +static void vulkan_overlay_enable(void *data, bool enable) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + vk->overlay.enable = enable; + if (vk->fullscreen) + gfx_ctx_ctl(GFX_CTL_SHOW_MOUSE, &enable); +} + +static void vulkan_overlay_full_screen(void *data, bool enable) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + vk->overlay.full_screen = enable; +} + +static void vulkan_overlay_free(vk_t *vk) +{ + unsigned i; + if (!vk) + return; + + free(vk->overlay.vertex); + for (i = 0; i < vk->overlay.count; i++) + if (vk->overlay.images[i].memory != VK_NULL_HANDLE) + vulkan_destroy_texture(vk->context->device, &vk->overlay.images[i]); + + memset(&vk->overlay, 0, sizeof(vk->overlay)); +} + +static void vulkan_overlay_set_alpha(void *data, unsigned image, float mod) +{ + vk_t *vk = (vk_t*)data; + struct vk_vertex *pv; + unsigned i; + + if (!vk) + return; + + pv = &vk->overlay.vertex[image * 4]; + for (i = 0; i < 4; i++) + { + pv[i].color.r = 1.0f; + pv[i].color.g = 1.0f; + pv[i].color.b = 1.0f; + pv[i].color.a = mod; + } +} + +static void vulkan_render_overlay(vk_t *vk) +{ + unsigned width, height; + unsigned i; + struct video_viewport vp; + + if (!vk) + return; + + video_driver_get_size(&width, &height); + vp = vk->vp; + vulkan_set_viewport(vk, width, height, vk->overlay.full_screen, false); + + for (i = 0; i < vk->overlay.count; i++) + { + struct vk_draw_triangles call; + struct vk_buffer_range range; + if (!vulkan_buffer_chain_alloc(vk->context, &vk->chain->vbo, + 4 * sizeof(struct vk_vertex), &range)) + break; + + memcpy(range.data, &vk->overlay.vertex[i * 4], 4 * sizeof(struct vk_vertex)); + + memset(&call, 0, sizeof(call)); + call.pipeline = vk->display.pipelines[3]; /* Strip with blend */ + call.texture = &vk->overlay.images[i]; + call.sampler = vk->samplers.linear; + call.mvp = &vk->mvp; + call.vbo = ⦥ + call.vertices = 4; + vulkan_draw_triangles(vk, &call); + } + + /* Restore the viewport so we don't mess with recording. */ + vk->vp = vp; +} + +static void vulkan_overlay_vertex_geom(void *data, unsigned image, + float x, float y, + float w, float h) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + struct vk_vertex *pv = &vk->overlay.vertex[4 * image]; + pv[0].x = x; + pv[0].y = y; + pv[1].x = x; + pv[1].y = y + h; + pv[2].x = x + w; + pv[2].y = y; + pv[3].x = x + w; + pv[3].y = y + h; +} + +static void vulkan_overlay_tex_geom(void *data, unsigned image, + float x, float y, + float w, float h) +{ + vk_t *vk = (vk_t*)data; + if (!vk) + return; + + struct vk_vertex *pv = &vk->overlay.vertex[4 * image]; + pv[0].tex_x = x; + pv[0].tex_y = y; + pv[1].tex_x = x; + pv[1].tex_y = y + h; + pv[2].tex_x = x + w; + pv[2].tex_y = y; + pv[3].tex_x = x + w; + pv[3].tex_y = y + h; +} + +static bool vulkan_overlay_load(void *data, + const void *image_data, unsigned num_images) +{ + const struct texture_image *images = (const struct texture_image*)image_data; + vk_t *vk = (vk_t*)data; + unsigned i, j; + static const struct vk_color white = { + 1.0f, 1.0f, 1.0f, 1.0f, + }; + + if (!vk) + return false; + + slock_lock(vk->context->queue_lock); + vkQueueWaitIdle(vk->context->queue); + slock_unlock(vk->context->queue_lock); + vulkan_overlay_free(vk); + + vk->overlay.images = (struct vk_texture*)calloc(num_images, sizeof(*vk->overlay.images)); + if (!vk->overlay.images) + goto error; + vk->overlay.count = num_images; + + vk->overlay.vertex = (struct vk_vertex*)calloc(4 * num_images, sizeof(*vk->overlay.vertex)); + if (!vk->overlay.vertex) + goto error; + + for (i = 0; i < num_images; i++) + { + vk->overlay.images[i] = vulkan_create_texture(vk, NULL, + images[i].width, images[i].height, + VK_FORMAT_B8G8R8A8_UNORM, images[i].pixels, + NULL, VULKAN_TEXTURE_STATIC); + + vulkan_overlay_tex_geom(vk, i, 0, 0, 1, 1); + vulkan_overlay_vertex_geom(vk, i, 0, 0, 1, 1); + for (j = 0; j < 4; j++) + vk->overlay.vertex[4 * i + j].color = white; + } + + return true; + +error: + vulkan_overlay_free(vk); + return false; +} + +static const video_overlay_interface_t vulkan_overlay_interface = { + vulkan_overlay_enable, + vulkan_overlay_load, + vulkan_overlay_tex_geom, + vulkan_overlay_vertex_geom, + vulkan_overlay_full_screen, + vulkan_overlay_set_alpha, +}; + +static void vulkan_get_overlay_interface(void *data, + const video_overlay_interface_t **iface) +{ + (void)data; + *iface = &vulkan_overlay_interface; +} +#endif + +video_driver_t video_vulkan = { + vulkan_init, + vulkan_frame, + vulkan_set_nonblock_state, + vulkan_alive, + vulkan_focus, + vulkan_suppress_screensaver, + vulkan_has_windowed, + vulkan_set_shader, + vulkan_free, + "vulkan", + vulkan_set_viewport, + vulkan_set_rotation, + vulkan_viewport_info, + vulkan_read_viewport, + NULL, /* vulkan_read_frame_raw */ + +#ifdef HAVE_OVERLAY + vulkan_get_overlay_interface, +#else + NULL, +#endif + vulkan_get_poke_interface, + NULL, /* vulkan_wrap_type_to_enum */ +}; + diff --git a/gfx/drivers/vulkan_shaders/Makefile b/gfx/drivers/vulkan_shaders/Makefile new file mode 100644 index 0000000000..e33ac65d2a --- /dev/null +++ b/gfx/drivers/vulkan_shaders/Makefile @@ -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 diff --git a/gfx/drivers/vulkan_shaders/alpha_blend.frag b/gfx/drivers/vulkan_shaders/alpha_blend.frag new file mode 100644 index 0000000000..7ea3c8a1e2 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/alpha_blend.frag @@ -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); +} diff --git a/gfx/drivers/vulkan_shaders/alpha_blend.frag.inc b/gfx/drivers/vulkan_shaders/alpha_blend.frag.inc new file mode 100644 index 0000000000..f62db944b5 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/alpha_blend.frag.inc @@ -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; diff --git a/gfx/drivers/vulkan_shaders/alpha_blend.vert b/gfx/drivers/vulkan_shaders/alpha_blend.vert new file mode 100644 index 0000000000..6edc2fe7ba --- /dev/null +++ b/gfx/drivers/vulkan_shaders/alpha_blend.vert @@ -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; +} diff --git a/gfx/drivers/vulkan_shaders/alpha_blend.vert.inc b/gfx/drivers/vulkan_shaders/alpha_blend.vert.inc new file mode 100644 index 0000000000..54f5bfce2f --- /dev/null +++ b/gfx/drivers/vulkan_shaders/alpha_blend.vert.inc @@ -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; diff --git a/gfx/drivers/vulkan_shaders/font.vert b/gfx/drivers/vulkan_shaders/font.vert new file mode 100644 index 0000000000..6edc2fe7ba --- /dev/null +++ b/gfx/drivers/vulkan_shaders/font.vert @@ -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; +} diff --git a/gfx/drivers/vulkan_shaders/font.vert.inc b/gfx/drivers/vulkan_shaders/font.vert.inc new file mode 100644 index 0000000000..8c0cff5409 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/font.vert.inc @@ -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; diff --git a/gfx/drivers/vulkan_shaders/opaque.frag b/gfx/drivers/vulkan_shaders/opaque.frag new file mode 100644 index 0000000000..fe71e14856 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/opaque.frag @@ -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); +} diff --git a/gfx/drivers/vulkan_shaders/opaque.frag.inc b/gfx/drivers/vulkan_shaders/opaque.frag.inc new file mode 100644 index 0000000000..03fd2ff4e7 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/opaque.frag.inc @@ -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; diff --git a/gfx/drivers/vulkan_shaders/opaque.vert b/gfx/drivers/vulkan_shaders/opaque.vert new file mode 100644 index 0000000000..9e6425a87f --- /dev/null +++ b/gfx/drivers/vulkan_shaders/opaque.vert @@ -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; +} diff --git a/gfx/drivers/vulkan_shaders/opaque.vert.inc b/gfx/drivers/vulkan_shaders/opaque.vert.inc new file mode 100644 index 0000000000..42fb461c4f --- /dev/null +++ b/gfx/drivers/vulkan_shaders/opaque.vert.inc @@ -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; diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 6fe20eb9fd..92005c4db6 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -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"); diff --git a/gfx/drivers_context/wayland_ctx_vulkan.c b/gfx/drivers_context/wayland_ctx_vulkan.c new file mode 100644 index 0000000000..58c2abdb24 --- /dev/null +++ b/gfx/drivers_context/wayland_ctx_vulkan.c @@ -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 . + */ + +#define VK_USE_PLATFORM_WAYLAND_KHR +#include "../common/vulkan_common.h" +#include "../video_context_driver.h" + +#include +#include +#include + +#include + +#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, +}; diff --git a/gfx/drivers_font/gl_raster_font.c b/gfx/drivers_font/gl_raster_font.c index 73cc1f33cf..4bd2d6c688 100644 --- a/gfx/drivers_font/gl_raster_font.c +++ b/gfx/drivers_font/gl_raster_font.c @@ -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; diff --git a/gfx/drivers_font/vulkan_raster_font.c b/gfx/drivers_font/vulkan_raster_font.c new file mode 100644 index 0000000000..5cd0585b62 --- /dev/null +++ b/gfx/drivers_font/vulkan_raster_font.c @@ -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 . + */ + +#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 +}; diff --git a/gfx/drivers_shader/glslang_util.cpp b/gfx/drivers_shader/glslang_util.cpp new file mode 100644 index 0000000000..8560968161 --- /dev/null +++ b/gfx/drivers_shader/glslang_util.cpp @@ -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 . + */ + +#include +#include +#include + +#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 *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 &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 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; +} + diff --git a/gfx/drivers_shader/glslang_util.hpp b/gfx/drivers_shader/glslang_util.hpp new file mode 100644 index 0000000000..7602e6ff8e --- /dev/null +++ b/gfx/drivers_shader/glslang_util.hpp @@ -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 . + */ + +#ifndef GLSLANG_UTIL_HPP +#define GLSLANG_UTIL_HPP + +#include +#include + +struct glslang_output +{ + std::vector vertex; + std::vector fragment; +}; + +bool glslang_compile_shader(const char *shader_path, glslang_output *output); + + +#endif + diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp new file mode 100644 index 0000000000..bd8bb4521c --- /dev/null +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -0,0 +1,1492 @@ +/* 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 . + */ + +#include "shader_vulkan.h" +#include "glslang_util.hpp" +#include +#include +#include +#include +#include +#include +#include "../drivers/vulkan_shaders/opaque.vert.inc" +#include "../drivers/vulkan_shaders/opaque.frag.inc" + +#include "../../general.h" + +using namespace std; + +static uint32_t 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(); +} + +static uint32_t 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 find_memory_type(mem_props, device_reqs, 0); +} + +static void build_identity_matrix(float *data) +{ + data[ 0] = 1.0f; + data[ 1] = 0.0f; + data[ 2] = 0.0f; + data[ 3] = 0.0f; + data[ 4] = 0.0f; + data[ 5] = 1.0f; + data[ 6] = 0.0f; + data[ 7] = 0.0f; + data[ 8] = 0.0f; + data[ 9] = 0.0f; + data[10] = 1.0f; + data[11] = 0.0f; + data[12] = 0.0f; + data[13] = 0.0f; + data[14] = 0.0f; + data[15] = 1.0f; +} + +static void build_vec4(float *data, unsigned width, unsigned height) +{ + data[0] = float(width); + data[1] = float(height); + data[2] = 1.0f / float(width); + data[3] = 1.0f / float(height); +} + +struct Size2D +{ + unsigned width, height; +}; + +struct Texture +{ + vulkan_filter_chain_texture texture; + vulkan_filter_chain_filter filter; +}; + +class DeferredDisposer +{ + public: + DeferredDisposer(vector> &calls) : calls(calls) {} + + void defer(function func) + { + calls.push_back(move(func)); + } + + private: + vector> &calls; +}; + +class Buffer +{ + public: + Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, + size_t size, VkBufferUsageFlags usage); + ~Buffer(); + + size_t get_size() const { return size; } + void *map(); + void unmap(); + + const VkBuffer &get_buffer() const { return buffer; } + + private: + VkDevice device; + VkBuffer buffer; + VkDeviceMemory memory; + size_t size; +}; + +class Framebuffer +{ + public: + Framebuffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, + const Size2D &max_size, VkFormat format); + + ~Framebuffer(); + Framebuffer(Framebuffer&&) = delete; + void operator=(Framebuffer&&) = delete; + + void set_size(DeferredDisposer &disposer, const Size2D &size); + + const Size2D &get_size() const { return size; } + VkImage get_image() const { return image; } + VkImageView get_view() const { return view; } + VkFramebuffer get_framebuffer() const { return framebuffer; } + VkRenderPass get_render_pass() const { return render_pass; } + + private: + VkDevice device = VK_NULL_HANDLE; + const VkPhysicalDeviceMemoryProperties &memory_properties; + VkImage image = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; + Size2D size; + VkFormat format; + + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkRenderPass render_pass = VK_NULL_HANDLE; + + struct + { + size_t size = 0; + uint32_t type = 0; + VkDeviceMemory memory = VK_NULL_HANDLE; + } memory; + + void init(DeferredDisposer *disposer); + void init_framebuffer(); + void init_render_pass(); +}; + +class Pass +{ + public: + Pass(VkDevice device, const VkPhysicalDeviceMemoryProperties &memory_properties, + VkPipelineCache cache, unsigned num_sync_indices, bool final_pass) : + device(device), + memory_properties(memory_properties), + cache(cache), + num_sync_indices(num_sync_indices), + final_pass(final_pass) + {} + + ~Pass(); + + Pass(Pass&&) = delete; + void operator=(Pass&&) = delete; + + const Framebuffer &get_framebuffer() const + { + return *framebuffer; + } + + Size2D set_pass_info( + const Size2D &max_original, + const Size2D &max_source, + const vulkan_filter_chain_swapchain_info &swapchain, + const vulkan_filter_chain_pass_info &info); + + void set_shader(VkShaderStageFlags stage, + const uint32_t *spirv, + size_t spirv_words); + + bool build(); + + void build_commands( + DeferredDisposer &disposer, + VkCommandBuffer cmd, + const Texture &original, + const Texture &source, + const VkViewport &vp, + const float *mvp); + + void notify_sync_index(unsigned index) + { + sync_index = index; + } + + vulkan_filter_chain_filter get_source_filter() const + { + return pass_info.source_filter; + } + + private: + struct UBO + { + float MVP[16]; + float output_size[4]; + float original_size[4]; + float source_size[4]; + }; + + VkDevice device; + const VkPhysicalDeviceMemoryProperties &memory_properties; + VkPipelineCache cache; + unsigned num_sync_indices; + unsigned sync_index; + bool final_pass; + + Size2D get_output_size(const Size2D &original_size, const Size2D &max_source) const; + + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; + VkDescriptorSetLayout set_layout = VK_NULL_HANDLE; + VkDescriptorPool pool = VK_NULL_HANDLE; + VkSampler samplers[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; + + vector> ubos; + unique_ptr vbo; + vector sets; + + Size2D current_framebuffer_size; + VkViewport current_viewport; + vulkan_filter_chain_pass_info pass_info; + + vector vertex_shader; + vector fragment_shader; + unique_ptr framebuffer; + VkRenderPass swapchain_render_pass; + + void clear_vk(); + bool init_pipeline(); + bool init_pipeline_layout(); + bool init_buffers(); + bool init_samplers(); + + void image_layout_transition(VkDevice device, + VkCommandBuffer cmd, VkImage image, + VkImageLayout old_layout, VkImageLayout new_layout, + VkAccessFlags srcAccess, VkAccessFlags dstAccess, + VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages); + + void update_descriptor_set( + const Texture &original, + const Texture &source); + + void set_texture(VkDescriptorSet set, unsigned binding, + const Texture &texture); + + void set_uniform_buffer(VkDescriptorSet set, unsigned binding, + VkBuffer buffer, + VkDeviceSize offset, + VkDeviceSize range); +}; + +// struct here since we're implementing the opaque typedef from C. +struct vulkan_filter_chain +{ + public: + vulkan_filter_chain(const vulkan_filter_chain_create_info &info); + ~vulkan_filter_chain(); + + inline void set_shader_preset(unique_ptr shader) + { + shader_preset = move(shader); + } + + inline video_shader *get_shader_preset() + { + return shader_preset.get(); + } + + void set_pass_info(unsigned pass, const vulkan_filter_chain_pass_info &info); + void set_shader(unsigned pass, VkShaderStageFlags stage, + const uint32_t *spirv, size_t spirv_words); + + bool init(); + bool update_swapchain_info(const vulkan_filter_chain_swapchain_info &info); + + void notify_sync_index(unsigned index); + void set_input_texture(const vulkan_filter_chain_texture &texture); + void build_offscreen_passes(VkCommandBuffer cmd, const VkViewport &vp); + void build_viewport_pass(VkCommandBuffer cmd, const VkViewport &vp, const float *mvp); + + private: + VkDevice device; + const VkPhysicalDeviceMemoryProperties &memory_properties; + VkPipelineCache cache; + vector> passes; + vector pass_info; + vector>> deferred_calls; + + vulkan_filter_chain_texture input_texture; + + Size2D max_input_size; + vulkan_filter_chain_swapchain_info swapchain_info; + unsigned current_sync_index; + + unique_ptr shader_preset; + + void flush(); + + void set_num_passes(unsigned passes); + void execute_deferred(); + void set_num_sync_indices(unsigned num_indices); + void set_swapchain_info(const vulkan_filter_chain_swapchain_info &info); +}; + +vulkan_filter_chain::vulkan_filter_chain(const vulkan_filter_chain_create_info &info) + : device(info.device), + memory_properties(*info.memory_properties), + cache(info.pipeline_cache) +{ + max_input_size = { info.max_input_size.width, info.max_input_size.height }; + set_swapchain_info(info.swapchain); + set_num_passes(info.num_passes); +} + +vulkan_filter_chain::~vulkan_filter_chain() +{ + flush(); +} + +void vulkan_filter_chain::set_swapchain_info(const vulkan_filter_chain_swapchain_info &info) +{ + swapchain_info = info; + set_num_sync_indices(info.num_indices); +} + +void vulkan_filter_chain::set_num_sync_indices(unsigned num_indices) +{ + execute_deferred(); + deferred_calls.resize(num_indices); +} + +void vulkan_filter_chain::notify_sync_index(unsigned index) +{ + auto &calls = deferred_calls[index]; + for (auto &call : calls) + call(); + calls.clear(); + + current_sync_index = index; + + for (auto &pass : passes) + pass->notify_sync_index(index); +} + +void vulkan_filter_chain::set_num_passes(unsigned num_passes) +{ + pass_info.resize(num_passes); + passes.reserve(num_passes); + for (unsigned i = 0; i < num_passes; i++) + { + passes.emplace_back(new Pass(device, memory_properties, + cache, deferred_calls.size(), i + 1 == num_passes)); + } +} + +bool vulkan_filter_chain::update_swapchain_info(const vulkan_filter_chain_swapchain_info &info) +{ + flush(); + set_swapchain_info(info); + return init(); +} + +void vulkan_filter_chain::set_pass_info(unsigned pass, + const vulkan_filter_chain_pass_info &info) +{ + pass_info[pass] = info; +} + +void vulkan_filter_chain::set_shader(unsigned pass, VkShaderStageFlags stage, + const uint32_t *spirv, size_t spirv_words) +{ + passes[pass]->set_shader(stage, spirv, spirv_words); +} + +void vulkan_filter_chain::set_input_texture(const vulkan_filter_chain_texture &texture) +{ + input_texture = texture; +} + +void vulkan_filter_chain::execute_deferred() +{ + for (auto &calls : deferred_calls) + { + for (auto &call : calls) + call(); + calls.clear(); + } +} + +void vulkan_filter_chain::flush() +{ + vkDeviceWaitIdle(device); + execute_deferred(); +} + +bool vulkan_filter_chain::init() +{ + Size2D source = max_input_size; + + for (unsigned i = 0; i < passes.size(); i++) + { + auto &pass = passes[i]; + source = pass->set_pass_info(max_input_size, source, swapchain_info, pass_info[i]); + if (!pass->build()) + return false; + } + + return true; +} + +void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd, + const VkViewport &vp) +{ + DeferredDisposer disposer(deferred_calls[current_sync_index]); + const Texture original = { input_texture, passes.front()->get_source_filter() }; + Texture source = { input_texture, passes.front()->get_source_filter() }; + + for (unsigned i = 0; i < passes.size() - 1; i++) + { + passes[i]->build_commands(disposer, cmd, + original, source, vp, nullptr); + + auto &fb = passes[i]->get_framebuffer(); + source.texture.view = fb.get_view(); + source.texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + source.texture.width = fb.get_size().width; + source.texture.height = fb.get_size().height; + source.filter = passes[i + 1]->get_source_filter(); + } +} + +void vulkan_filter_chain::build_viewport_pass(VkCommandBuffer cmd, const VkViewport &vp, const float *mvp) +{ + DeferredDisposer disposer(deferred_calls[current_sync_index]); + + const Texture original = { input_texture, passes.front()->get_source_filter() }; + Texture source; + + if (passes.size() == 1) + source = { input_texture, passes.back()->get_source_filter() }; + else + { + auto &fb = passes[passes.size() - 2]->get_framebuffer(); + source.texture.view = fb.get_view(); + source.texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + source.texture.width = fb.get_size().width; + source.texture.height = fb.get_size().height; + source.filter = passes.back()->get_source_filter(); + } + + passes.back()->build_commands(disposer, cmd, + original, source, vp, mvp); +} + +Buffer::Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, + size_t size, VkBufferUsageFlags usage) : + device(device), size(size) +{ + VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + info.size = size; + info.usage = usage; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + vkCreateBuffer(device, &info, nullptr, &buffer); + + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements(device, buffer, &mem_reqs); + + VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + alloc.allocationSize = mem_reqs.size; + + alloc.memoryTypeIndex = find_memory_type(mem_props, mem_reqs.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(device, &alloc, NULL, &memory); + vkBindBufferMemory(device, buffer, memory, 0); +} + +void *Buffer::map() +{ + void *ptr = nullptr; + if (vkMapMemory(device, memory, 0, size, 0, &ptr) == VK_SUCCESS) + return ptr; + else + return nullptr; +} + +void Buffer::unmap() +{ + vkUnmapMemory(device, memory); +} + +Buffer::~Buffer() +{ + if (memory != VK_NULL_HANDLE) + vkFreeMemory(device, memory, nullptr); + if (buffer != VK_NULL_HANDLE) + vkDestroyBuffer(device, buffer, nullptr); +} + +Pass::~Pass() +{ + clear_vk(); +} + +void Pass::set_shader(VkShaderStageFlags stage, + const uint32_t *spirv, + size_t spirv_words) +{ + if (stage == VK_SHADER_STAGE_VERTEX_BIT) + { + vertex_shader.clear(); + vertex_shader.insert(end(vertex_shader), spirv, spirv + spirv_words); + } + else if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) + { + fragment_shader.clear(); + fragment_shader.insert(end(fragment_shader), spirv, spirv + spirv_words); + } +} + +Size2D Pass::get_output_size(const Size2D &original, const Size2D &source) const +{ + float width, height; + switch (pass_info.scale_type_x) + { + case VULKAN_FILTER_CHAIN_SCALE_ORIGINAL: + width = float(original.width) * pass_info.scale_x; + break; + + case VULKAN_FILTER_CHAIN_SCALE_SOURCE: + width = float(source.width) * pass_info.scale_x; + break; + + case VULKAN_FILTER_CHAIN_SCALE_VIEWPORT: + width = current_viewport.width * pass_info.scale_x; + break; + + case VULKAN_FILTER_CHAIN_SCALE_ABSOLUTE: + width = pass_info.scale_x; + break; + + default: + width = 0.0f; + } + + switch (pass_info.scale_type_y) + { + case VULKAN_FILTER_CHAIN_SCALE_ORIGINAL: + height = float(original.height) * pass_info.scale_y; + break; + + case VULKAN_FILTER_CHAIN_SCALE_SOURCE: + height = float(source.height) * pass_info.scale_y; + break; + + case VULKAN_FILTER_CHAIN_SCALE_VIEWPORT: + height = current_viewport.height * pass_info.scale_y; + break; + + case VULKAN_FILTER_CHAIN_SCALE_ABSOLUTE: + height = pass_info.scale_y; + break; + + default: + height = 0.0f; + } + + return { unsigned(roundf(width)), unsigned(roundf(height)) }; +} + +Size2D Pass::set_pass_info( + const Size2D &max_original, + const Size2D &max_source, + const vulkan_filter_chain_swapchain_info &swapchain, + const vulkan_filter_chain_pass_info &info) +{ + clear_vk(); + + current_viewport = swapchain.viewport; + pass_info = info; + + num_sync_indices = swapchain.num_indices; + sync_index = 0; + + current_framebuffer_size = get_output_size(max_original, max_source); + swapchain_render_pass = swapchain.render_pass; + return current_framebuffer_size; +} + +void Pass::clear_vk() +{ + if (pool != VK_NULL_HANDLE) + vkDestroyDescriptorPool(device, pool, nullptr); + if (pipeline != VK_NULL_HANDLE) + vkDestroyPipeline(device, pipeline, nullptr); + if (set_layout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(device, set_layout, nullptr); + if (pipeline_layout != VK_NULL_HANDLE) + vkDestroyPipelineLayout(device, pipeline_layout, nullptr); + + for (auto &samp : samplers) + { + if (samp != VK_NULL_HANDLE) + vkDestroySampler(device, samp, nullptr); + samp = VK_NULL_HANDLE; + } + + pool = VK_NULL_HANDLE; + pipeline = VK_NULL_HANDLE; + set_layout = VK_NULL_HANDLE; + ubos.clear(); + vbo.reset(); +} + +bool Pass::init_pipeline_layout() +{ + vector bindings; + vector desc_counts; + + // TODO: Expand this a lot, need to reflect shaders to figure this out. + bindings.push_back({ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + nullptr }); + + bindings.push_back({ 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT, + nullptr }); + + bindings.push_back({ 2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT, + nullptr }); + + desc_counts.push_back({ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }); + desc_counts.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }); + desc_counts.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }); + + VkDescriptorSetLayoutCreateInfo set_layout_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + set_layout_info.bindingCount = bindings.size(); + set_layout_info.pBindings = bindings.data(); + + if (vkCreateDescriptorSetLayout(device, &set_layout_info, NULL, &set_layout) != VK_SUCCESS) + return false; + + VkPipelineLayoutCreateInfo layout_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = &set_layout; + + if (vkCreatePipelineLayout(device, &layout_info, NULL, &pipeline_layout) != VK_SUCCESS) + return false; + + VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + pool_info.maxSets = num_sync_indices; + pool_info.poolSizeCount = desc_counts.size(); + pool_info.pPoolSizes = desc_counts.data(); + if (vkCreateDescriptorPool(device, &pool_info, nullptr, &pool) != VK_SUCCESS) + return false; + + VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + alloc_info.descriptorPool = pool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &set_layout; + + sets.resize(num_sync_indices); + for (unsigned i = 0; i < num_sync_indices; i++) + vkAllocateDescriptorSets(device, &alloc_info, &sets[i]); + + return true; +} + +bool Pass::init_pipeline() +{ + if (!init_pipeline_layout()) + return false; + + // Input assembly + VkPipelineInputAssemblyStateCreateInfo input_assembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + + // VAO state + VkVertexInputAttributeDescription attributes[2] = {{0}}; + VkVertexInputBindingDescription binding = {0}; + + attributes[0].location = 0; + attributes[0].binding = 0; + attributes[0].format = VK_FORMAT_R32G32_SFLOAT; + attributes[0].offset = 0; + attributes[1].location = 1; + attributes[1].binding = 0; + attributes[1].format = VK_FORMAT_R32G32_SFLOAT; + attributes[1].offset = 2 * sizeof(float); + + binding.binding = 0; + binding.stride = 4 * sizeof(float); + 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; + + // Raster state + VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + raster.polygonMode = VK_POLYGON_MODE_FILL; + raster.cullMode = VK_CULL_MODE_NONE; + raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + raster.depthClampEnable = false; + raster.rasterizerDiscardEnable = false; + raster.depthBiasEnable = false; + raster.lineWidth = 1.0f; + + // Blend state + VkPipelineColorBlendAttachmentState blend_attachment = {0}; + VkPipelineColorBlendStateCreateInfo blend = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + blend_attachment.blendEnable = false; + blend_attachment.colorWriteMask = 0xf; + blend.attachmentCount = 1; + blend.pAttachments = &blend_attachment; + + // Viewport state + VkPipelineViewportStateCreateInfo viewport = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + viewport.viewportCount = 1; + viewport.scissorCount = 1; + + // Depth-stencil state + 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; + depth_stencil.minDepthBounds = 0.0f; + depth_stencil.maxDepthBounds = 1.0f; + + // Multisample state + VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + // Dynamic state + VkPipelineDynamicStateCreateInfo dynamic = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + static const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + dynamic.pDynamicStates = dynamics; + dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]); + + // Shaders + VkPipelineShaderStageCreateInfo shader_stages[2] = { + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, + }; + + VkShaderModuleCreateInfo module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; + module_info.codeSize = vertex_shader.size() * sizeof(uint32_t); + module_info.pCode = vertex_shader.data(); + shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_stages[0].pName = "main"; + vkCreateShaderModule(device, &module_info, NULL, &shader_stages[0].module); + + module_info.codeSize = fragment_shader.size() * sizeof(uint32_t); + module_info.pCode = fragment_shader.data(); + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].pName = "main"; + vkCreateShaderModule(device, &module_info, NULL, &shader_stages[1].module); + + 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 = final_pass ? swapchain_render_pass : framebuffer->get_render_pass(); + pipe.layout = pipeline_layout; + + if (vkCreateGraphicsPipelines(device, cache, 1, &pipe, NULL, &pipeline) != VK_SUCCESS) + { + vkDestroyShaderModule(device, shader_stages[0].module, NULL); + vkDestroyShaderModule(device, shader_stages[1].module, NULL); + return false; + } + + vkDestroyShaderModule(device, shader_stages[0].module, NULL); + vkDestroyShaderModule(device, shader_stages[1].module, NULL); + return true; +} + +bool Pass::init_samplers() +{ + VkSamplerCreateInfo info = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + info.magFilter = VK_FILTER_NEAREST; + info.minFilter = VK_FILTER_NEAREST; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.mipLodBias = 0.0f; + info.maxAnisotropy = 1.0f; + info.compareEnable = false; + info.minLod = 0.0f; + info.maxLod = 0.0f; + info.unnormalizedCoordinates = false; + info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + + if (vkCreateSampler(device, &info, NULL, &samplers[VULKAN_FILTER_CHAIN_NEAREST]) != VK_SUCCESS) + return false; + + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + + if (vkCreateSampler(device, &info, NULL, &samplers[VULKAN_FILTER_CHAIN_LINEAR]) != VK_SUCCESS) + return false; + + return true; +} + +bool Pass::init_buffers() +{ + // The final pass uses an MVP designed for [0, 1] range VBO. + // For in-between passes, we just go with identity matrices, so keep it simple. + float pos_min = final_pass ? 0.0f : -1.0f; + + const float vbo_data[] = { + pos_min, pos_min, 0.0f, 0.0f, + pos_min, +1.0f, 0.0f, 1.0f, + 1.0f, pos_min, 1.0f, 0.0f, + 1.0f, +1.0f, 1.0f, 1.0f, + }; + + ubos.clear(); + for (unsigned i = 0; i < num_sync_indices; i++) + ubos.emplace_back(new Buffer(device, memory_properties, sizeof(UBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)); + vbo = unique_ptr(new Buffer(device, memory_properties, sizeof(vbo_data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); + + void *ptr = vbo->map(); + memcpy(ptr, vbo_data, sizeof(vbo_data)); + vbo->unmap(); + return true; +} + +bool Pass::build() +{ + if (!final_pass) + { + framebuffer = unique_ptr( + new Framebuffer(device, memory_properties, current_framebuffer_size, + pass_info.rt_format)); + } + + if (!init_pipeline()) + return false; + + if (!init_buffers()) + return false; + + if (!init_samplers()) + return false; + + return true; +} + +void Pass::image_layout_transition(VkDevice device, + 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, nullptr, + 0, nullptr, + 1, &barrier); +} + +void Pass::set_uniform_buffer(VkDescriptorSet set, unsigned binding, + VkBuffer buffer, + VkDeviceSize offset, + VkDeviceSize range) +{ + VkDescriptorBufferInfo buffer_info; + buffer_info.buffer = buffer; + buffer_info.offset = offset; + buffer_info.range = range; + + VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = set; + write.dstBinding = binding; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write.pBufferInfo = &buffer_info; + + vkUpdateDescriptorSets(device, 1, &write, 0, NULL); +} + +void Pass::set_texture(VkDescriptorSet set, unsigned binding, + const Texture &texture) +{ + VkDescriptorImageInfo image_info; + image_info.sampler = samplers[texture.filter]; + image_info.imageView = texture.texture.view; + image_info.imageLayout = texture.texture.layout; + + VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + write.dstSet = set; + write.dstBinding = binding; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.pImageInfo = &image_info; + + vkUpdateDescriptorSets(device, 1, &write, 0, nullptr); +} + +void Pass::update_descriptor_set( + const Texture &original, + const Texture &source) +{ + set_uniform_buffer(sets[sync_index], 0, ubos[sync_index]->get_buffer(), 0, sizeof(UBO)); + set_texture(sets[sync_index], 1, original); + set_texture(sets[sync_index], 2, source); +} + +void Pass::build_commands( + DeferredDisposer &disposer, + VkCommandBuffer cmd, + const Texture &original, + const Texture &source, + const VkViewport &vp, + const float *mvp) +{ + current_viewport = vp; + auto size = get_output_size( + { original.texture.width, original.texture.height }, + { source.texture.width, source.texture.height }); + + if (size.width != current_framebuffer_size.width || size.height != current_framebuffer_size.height) + { + if (framebuffer) + framebuffer->set_size(disposer, size); + current_framebuffer_size = size; + } + + UBO *u = static_cast(ubos[sync_index]->map()); + + if (mvp) + memcpy(u->MVP, mvp, sizeof(float) * 16); + else + build_identity_matrix(u->MVP); + build_vec4(u->output_size, current_framebuffer_size.width, current_framebuffer_size.height); + build_vec4(u->original_size, original.texture.width, original.texture.height); + build_vec4(u->source_size, source.texture.width, source.texture.height); + ubos[sync_index]->unmap(); + + update_descriptor_set(original, source); + + // The final pass is always executed inside another render pass since + // the frontend will want to overlay various things on top for the passes that end + // up on-screen. + if (!final_pass) + { + // Render. + image_layout_transition(device, cmd, framebuffer->get_image(), + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + + VkRenderPassBeginInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; + VkClearValue clear_value; + clear_value.color.float32[0] = 0.0f; + clear_value.color.float32[1] = 0.0f; + clear_value.color.float32[2] = 0.0f; + clear_value.color.float32[3] = 1.0f; + rp_info.renderPass = framebuffer->get_render_pass(); + rp_info.framebuffer = framebuffer->get_framebuffer(); + rp_info.renderArea.extent.width = current_framebuffer_size.width; + rp_info.renderArea.extent.height = current_framebuffer_size.height; + rp_info.clearValueCount = 1; + rp_info.pClearValues = &clear_value; + vkCmdBeginRenderPass(cmd, &rp_info, VK_SUBPASS_CONTENTS_INLINE); + } + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, + 0, 1, &sets[sync_index], 0, nullptr); + + VkDeviceSize offset = 0; + vkCmdBindVertexBuffers(cmd, 0, 1, &vbo->get_buffer(), &offset); + + if (final_pass) + { + const VkRect2D sci = { + { int32_t(current_viewport.x), int32_t(current_viewport.y) }, + { uint32_t(current_viewport.width), uint32_t(current_viewport.height) }, + }; + vkCmdSetViewport(cmd, 0, 1, ¤t_viewport); + vkCmdSetScissor(cmd, 0, 1, &sci); + } + else + { + const VkViewport vp = { + 0.0f, 0.0f, + float(current_framebuffer_size.width), float(current_framebuffer_size.height), + 0.0f, 1.0f + }; + const VkRect2D sci = { + { 0, 0 }, + { current_framebuffer_size.width, current_framebuffer_size.height }, + }; + + vkCmdSetViewport(cmd, 0, 1, &vp); + vkCmdSetScissor(cmd, 0, 1, &sci); + } + + vkCmdDraw(cmd, 4, 1, 0, 0); + + if (!final_pass) + { + vkCmdEndRenderPass(cmd); + + // Barrier to sync with next pass. + image_layout_transition(device, cmd, framebuffer->get_image(), + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + } +} + +Framebuffer::Framebuffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, + const Size2D &max_size, VkFormat format) : + device(device), + memory_properties(mem_props), + size(max_size), + format(format) +{ + RARCH_LOG("[Vulkan filter chain]: Creating framebuffer %u x %u.\n", max_size.width, max_size.height); + init_render_pass(); + init(nullptr); +} + +void Framebuffer::init(DeferredDisposer *disposer) +{ + VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = format; + info.extent.width = size.width; + info.extent.height = size.height; + info.extent.depth = 1; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + vkCreateImage(device, &info, nullptr, &image); + + VkMemoryRequirements mem_reqs; + vkGetImageMemoryRequirements(device, image, &mem_reqs); + + VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + alloc.allocationSize = mem_reqs.size; + alloc.memoryTypeIndex = find_memory_type_fallback(memory_properties, mem_reqs.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + // Can reuse already allocated memory. + if (memory.size < mem_reqs.size || memory.type != alloc.memoryTypeIndex) + { + // Memory might still be in use since we don't want to totally stall + // the world for framebuffer recreation. + if (memory.memory != VK_NULL_HANDLE && disposer) + { + auto d = device; + auto m = memory.memory; + disposer->defer([=] { vkFreeMemory(d, m, nullptr); }); + } + + memory.type = alloc.memoryTypeIndex; + memory.size = mem_reqs.size; + vkAllocateMemory(device, &alloc, nullptr, &memory.memory); + } + + vkBindImageMemory(device, image, memory.memory, 0); + + VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = format; + view_info.image = image; + view_info.subresourceRange.baseMipLevel = 0; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.layerCount = 1; + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.components.r = VK_COMPONENT_SWIZZLE_R; + view_info.components.g = VK_COMPONENT_SWIZZLE_G; + view_info.components.b = VK_COMPONENT_SWIZZLE_B; + view_info.components.a = VK_COMPONENT_SWIZZLE_A; + vkCreateImageView(device, &view_info, nullptr, &view); + + init_framebuffer(); +} + +void Framebuffer::init_render_pass() +{ + VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; + VkAttachmentReference color_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + // We will always write to the entire framebuffer, + // so we don't really need to clear. + VkAttachmentDescription attachment = {0}; + attachment.format = format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + 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; + + VkSubpassDescription subpass = {0}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_ref; + + rp_info.attachmentCount = 1; + rp_info.pAttachments = &attachment; + rp_info.subpassCount = 1; + rp_info.pSubpasses = &subpass; + + vkCreateRenderPass(device, &rp_info, nullptr, &render_pass); +} + +void Framebuffer::init_framebuffer() +{ + VkFramebufferCreateInfo info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + info.renderPass = render_pass; + info.attachmentCount = 1; + info.pAttachments = &view; + info.width = size.width; + info.height = size.height; + info.layers = 1; + + vkCreateFramebuffer(device, &info, nullptr, &framebuffer); +} + +void Framebuffer::set_size(DeferredDisposer &disposer, const Size2D &size) +{ + this->size = size; + + RARCH_LOG("[Vulkan filter chain]: Updating framebuffer size %u x %u.\n", size.width, size.height); + + { + // The current framebuffers, etc, might still be in use + // so defer deletion. + // We'll most likely be able to reuse the memory, + // so don't free it here. + // + // Fake lambda init captures for C++11. + // + auto d = device; + auto i = image; + auto v = view; + auto fb = framebuffer; + disposer.defer([=] + { + if (fb != VK_NULL_HANDLE) + vkDestroyFramebuffer(d, fb, nullptr); + if (v != VK_NULL_HANDLE) + vkDestroyImageView(d, v, nullptr); + if (i != VK_NULL_HANDLE) + vkDestroyImage(d, i, nullptr); + }); + } + + init(&disposer); +} + +Framebuffer::~Framebuffer() +{ + if (framebuffer != VK_NULL_HANDLE) + vkDestroyFramebuffer(device, framebuffer, nullptr); + if (render_pass != VK_NULL_HANDLE) + vkDestroyRenderPass(device, render_pass, nullptr); + if (view != VK_NULL_HANDLE) + vkDestroyImageView(device, view, nullptr); + if (image != VK_NULL_HANDLE) + vkDestroyImage(device, image, nullptr); + if (memory.memory != VK_NULL_HANDLE) + vkFreeMemory(device, memory.memory, nullptr); +} + +// C glue +vulkan_filter_chain_t *vulkan_filter_chain_new( + const vulkan_filter_chain_create_info *info) +{ + return new vulkan_filter_chain(*info); +} + +vulkan_filter_chain_t *vulkan_filter_chain_create_default(const struct vulkan_filter_chain_create_info *info, vulkan_filter_chain_filter filter) +{ + auto tmpinfo = *info; + tmpinfo.num_passes = 1; + + unique_ptr chain{ new vulkan_filter_chain(tmpinfo) }; + if (!chain) + return nullptr; + + struct vulkan_filter_chain_pass_info pass_info; + memset(&pass_info, 0, sizeof(pass_info)); + pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + pass_info.scale_x = 1.0f; + pass_info.scale_y = 1.0f; + pass_info.rt_format = tmpinfo.swapchain.format; + pass_info.source_filter = filter; + chain->set_pass_info(0, pass_info); + + chain->set_shader(0, VK_SHADER_STAGE_VERTEX_BIT, (const uint32_t*)opaque_vert_spv, opaque_vert_spv_len / sizeof(uint32_t)); + chain->set_shader(0, VK_SHADER_STAGE_FRAGMENT_BIT, (const uint32_t*)opaque_frag_spv, opaque_frag_spv_len / sizeof(uint32_t)); + + if (!chain->init()) + return nullptr; + + return chain.release(); +} + +struct ConfigDeleter +{ + void operator()(config_file_t *conf) + { + if (conf) + config_file_free(conf); + } +}; + +vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulkan_filter_chain_create_info *info, + const char *path, vulkan_filter_chain_filter filter) +{ + unique_ptr shader{ new video_shader() }; + if (!shader) + return nullptr; + + unique_ptr conf{ config_file_new(path) }; + if (!path) + return nullptr; + + if (!video_shader_read_conf_cgp(conf.get(), shader.get())) + return nullptr; + + video_shader_resolve_relative(shader.get(), path); + video_shader_resolve_parameters(conf.get(), shader.get()); + + bool last_pass_is_fbo = shader->pass[shader->passes - 1].fbo.valid; + auto tmpinfo = *info; + tmpinfo.num_passes = shader->passes + (last_pass_is_fbo ? 1 : 0); + + unique_ptr chain{ new vulkan_filter_chain(tmpinfo) }; + if (!chain) + return nullptr; + + for (unsigned i = 0; i < shader->passes; i++) + { + const video_shader_pass *pass = &shader->pass[i]; + struct vulkan_filter_chain_pass_info pass_info; + memset(&pass_info, 0, sizeof(pass_info)); + + glslang_output output; + if (!glslang_compile_shader(pass->source.path, &output)) + { + RARCH_ERR("Failed to compile shader: \"%s\".\n", pass->source.path); + return nullptr; + } + + chain->set_shader(i, + VK_SHADER_STAGE_VERTEX_BIT, + output.vertex.data(), + output.vertex.size()); + + chain->set_shader(i, + VK_SHADER_STAGE_FRAGMENT_BIT, + output.fragment.data(), + output.fragment.size()); + + if (pass->filter == RARCH_FILTER_UNSPEC) + pass_info.source_filter = filter; + else + { + pass_info.source_filter = + pass->filter == RARCH_FILTER_LINEAR ? VULKAN_FILTER_CHAIN_LINEAR : + VULKAN_FILTER_CHAIN_NEAREST; + } + + if (!pass->fbo.valid) + { + pass_info.scale_type_x = i + 1 == shader->passes ? VULKAN_FILTER_CHAIN_SCALE_VIEWPORT : VULKAN_FILTER_CHAIN_SCALE_SOURCE; + pass_info.scale_type_y = i + 1 == shader->passes ? VULKAN_FILTER_CHAIN_SCALE_VIEWPORT : VULKAN_FILTER_CHAIN_SCALE_SOURCE; + pass_info.scale_x = 1.0f; + pass_info.scale_y = 1.0f; + pass_info.rt_format = i + 1 == shader->passes ? tmpinfo.swapchain.format : VK_FORMAT_R8G8B8A8_UNORM; + } + else + { + // TODO: Add more general format spec. + pass_info.rt_format = VK_FORMAT_R8G8B8A8_UNORM; + if (pass->fbo.srgb_fbo) + pass_info.rt_format = VK_FORMAT_R8G8B8A8_SRGB; + else if (pass->fbo.fp_fbo) + pass_info.rt_format = VK_FORMAT_R16G16B16A16_SFLOAT; + + switch (pass->fbo.type_x) + { + case RARCH_SCALE_INPUT: + pass_info.scale_x = pass->fbo.scale_x; + pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_SOURCE; + break; + + case RARCH_SCALE_ABSOLUTE: + pass_info.scale_x = float(pass->fbo.abs_x); + pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_ABSOLUTE; + break; + + case RARCH_SCALE_VIEWPORT: + pass_info.scale_x = pass->fbo.scale_x; + pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + break; + } + + switch (pass->fbo.type_y) + { + case RARCH_SCALE_INPUT: + pass_info.scale_y = pass->fbo.scale_y; + pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_SOURCE; + break; + + case RARCH_SCALE_ABSOLUTE: + pass_info.scale_y = float(pass->fbo.abs_y); + pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_ABSOLUTE; + break; + + case RARCH_SCALE_VIEWPORT: + pass_info.scale_y = pass->fbo.scale_y; + pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + break; + } + } + + chain->set_pass_info(i, pass_info); + } + + if (last_pass_is_fbo) + { + struct vulkan_filter_chain_pass_info pass_info; + memset(&pass_info, 0, sizeof(pass_info)); + pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; + pass_info.scale_x = 1.0f; + pass_info.scale_y = 1.0f; + pass_info.rt_format = tmpinfo.swapchain.format; + pass_info.source_filter = filter; + chain->set_pass_info(shader->passes, pass_info); + + chain->set_shader(shader->passes, + VK_SHADER_STAGE_VERTEX_BIT, + (const uint32_t*)opaque_vert_spv, + opaque_vert_spv_len / sizeof(uint32_t)); + + chain->set_shader(shader->passes, + VK_SHADER_STAGE_FRAGMENT_BIT, + (const uint32_t*)opaque_frag_spv, + opaque_frag_spv_len / sizeof(uint32_t)); + } + + chain->set_shader_preset(move(shader)); + + if (!chain->init()) + return nullptr; + + return chain.release(); +} + +struct video_shader *vulkan_filter_chain_get_preset(vulkan_filter_chain_t *chain) +{ + return chain->get_shader_preset(); +} + +void vulkan_filter_chain_free(vulkan_filter_chain_t *chain) +{ + delete chain; +} + +void vulkan_filter_chain_set_shader(vulkan_filter_chain_t *chain, + unsigned pass, + VkShaderStageFlags stage, + const uint32_t *spirv, + size_t spirv_words) +{ + chain->set_shader(pass, stage, spirv, spirv_words); +} + +void vulkan_filter_chain_set_pass_info(vulkan_filter_chain_t *chain, + unsigned pass, + const struct vulkan_filter_chain_pass_info *info) +{ + chain->set_pass_info(pass, *info); +} + +bool vulkan_filter_chain_update_swapchain_info(vulkan_filter_chain_t *chain, + const vulkan_filter_chain_swapchain_info *info) +{ + return chain->update_swapchain_info(*info); +} + +void vulkan_filter_chain_notify_sync_index(vulkan_filter_chain_t *chain, + unsigned index) +{ + chain->notify_sync_index(index); +} + +bool vulkan_filter_chain_init(vulkan_filter_chain_t *chain) +{ + return chain->init(); +} + +void vulkan_filter_chain_set_input_texture(vulkan_filter_chain_t *chain, + const struct vulkan_filter_chain_texture *texture) +{ + chain->set_input_texture(*texture); +} + +void vulkan_filter_chain_build_offscreen_passes(vulkan_filter_chain_t *chain, + VkCommandBuffer cmd, const VkViewport *vp) +{ + chain->build_offscreen_passes(cmd, *vp); +} + +void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain, + VkCommandBuffer cmd, const VkViewport *vp, const float *mvp) +{ + chain->build_viewport_pass(cmd, *vp, mvp); +} + diff --git a/gfx/drivers_shader/shader_vulkan.h b/gfx/drivers_shader/shader_vulkan.h new file mode 100644 index 0000000000..d42cb86c61 --- /dev/null +++ b/gfx/drivers_shader/shader_vulkan.h @@ -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 . + */ + +#ifndef SHADER_VULKAN_H +#define SHADER_VULKAN_H + +#include +#include +#include + +#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 + diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 99ca2e271d..f92d0b4187 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -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, diff --git a/gfx/font_driver.h b/gfx/font_driver.h index 4a53472ed4..5f32cbad92 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -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; diff --git a/gfx/video_context_driver.c b/gfx/video_context_driver.c index f5bcaa9962..88779ba0a4 100644 --- a/gfx/video_context_driver.c +++ b/gfx/video_context_driver.c @@ -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; diff --git a/gfx/video_context_driver.h b/gfx/video_context_driver.h index f0ae458e6b..8dad181a5a 100644 --- a/gfx/video_context_driver.h +++ b/gfx/video_context_driver.h @@ -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; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index fa0a738b5a..7f2ad59d4e 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -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; } diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 5c77af9ec4..1f844126b7 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -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; diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 4ada660725..49da8f220f 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -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; } diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index 0f7462a2f7..d33af0eda5 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -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 diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index 9af65a455f..7450f1b2bc 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -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; diff --git a/libretro.h b/libretro.h index 5e927c4222..a2315480e9 100644 --- a/libretro.h +++ b/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; diff --git a/libretro_vulkan.h b/libretro_vulkan.h new file mode 100644 index 0000000000..2e7486ed31 --- /dev/null +++ b/libretro_vulkan.h @@ -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 + +#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 + diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 4b3b8767a6..bf520d88fe 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -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: diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 3f936b65bd..b66bae50f2 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -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); diff --git a/menu/drivers/zarch.c b/menu/drivers/zarch.c index 5cf6704a19..0a102916c1 100644 --- a/menu/drivers/zarch.c +++ b/menu/drivers/zarch.c @@ -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) diff --git a/menu/drivers_display/menu_display_vulkan.c b/menu/drivers_display/menu_display_vulkan.c new file mode 100644 index 0000000000..18c28fa129 --- /dev/null +++ b/menu/drivers_display/menu_display_vulkan.c @@ -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 . + */ + +#include + +#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", +}; diff --git a/menu/menu_display.c b/menu/menu_display.c index f6228eee7d..cc31f2b239 100644 --- a/menu/menu_display.c +++ b/menu/menu_display.c @@ -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; diff --git a/menu/menu_display.h b/menu/menu_display.h index 0d742904e0..c3b5c85e8c 100644 --- a/menu/menu_display.h +++ b/menu/menu_display.h @@ -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; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index d1f28b3539..653d1f6367 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -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; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 87c35c5759..225919cf42 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -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; diff --git a/menu/menu_hash.h b/menu/menu_hash.h index ce2b882343..f3df4426aa 100644 --- a/menu/menu_hash.h +++ b/menu/menu_hash.h @@ -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 diff --git a/menu/menu_shader.c b/menu/menu_shader.c index a76062c0d3..f10bb9f2fc 100644 --- a/menu/menu_shader.c +++ b/menu/menu_shader.c @@ -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); diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 2ad68a3b97..b62b44ae79 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -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 diff --git a/qb/config.params.sh b/qb/config.params.sh index 2913318ec7..41baddc386 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -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 diff --git a/record/drivers/record_ffmpeg.c b/record/drivers/record_ffmpeg.c index 37ee508eae..0d9518c8b9 100644 --- a/record/drivers/record_ffmpeg.c +++ b/record/drivers/record_ffmpeg.c @@ -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; } diff --git a/runloop.c b/runloop.c index 0836ca9053..aa1f5bfae9 100644 --- a/runloop.c +++ b/runloop.c @@ -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;