Merge branch 'master' of git://github.com/libretro/RetroArch

This commit is contained in:
Hans-Kristian Arntzen 2016-02-21 12:45:26 +01:00
commit 4259ea3d06
13 changed files with 1158 additions and 837 deletions

View File

@ -173,15 +173,17 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
VkFormat format, VkFormat format,
const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type) const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type)
{ {
VkDevice device = vk->context->device;
struct vk_texture tex; struct vk_texture tex;
VkMemoryRequirements mem_reqs;
VkSubresourceLayout layout;
VkDevice device = vk->context->device;
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT }; VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT };
VkMemoryRequirements mem_reqs; VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
VkSubresourceLayout layout; VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
memset(&tex, 0, sizeof(tex)); memset(&tex, 0, sizeof(tex));
@ -364,12 +366,12 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
if (initial && type == VULKAN_TEXTURE_STREAMED) if (initial && type == VULKAN_TEXTURE_STREAMED)
{ {
unsigned x, y;
uint8_t *dst = NULL;
const uint8_t *src = NULL;
void *ptr = NULL;
unsigned bpp = vulkan_format_to_bpp(tex.format); unsigned bpp = vulkan_format_to_bpp(tex.format);
unsigned stride = tex.width * bpp; 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); vkMapMemory(device, tex.memory, tex.offset, tex.size, 0, &ptr);
@ -382,20 +384,16 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
} }
else if (initial && type == VULKAN_TEXTURE_STATIC) 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; VkImageCopy region;
VkCommandBuffer staging; VkCommandBuffer staging;
unsigned bpp = vulkan_format_to_bpp(tex.format); unsigned bpp = vulkan_format_to_bpp(tex.format);
struct vk_texture tmp = vulkan_create_texture(vk, NULL, struct vk_texture tmp = vulkan_create_texture(vk, NULL,
width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING); width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING);
info.commandPool = vk->staging_pool; cmd_info.commandPool = vk->staging_pool;
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
info.commandBufferCount = 1; cmd_info.commandBufferCount = 1;
vkAllocateCommandBuffers(vk->context->device, &info, &staging); vkAllocateCommandBuffers(vk->context->device, &cmd_info, &staging);
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(staging, &begin_info); vkBeginCommandBuffer(staging, &begin_info);
@ -426,8 +424,10 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
1, &region); 1, &region);
vulkan_image_layout_transition(vk, staging, tex.image, vulkan_image_layout_transition(vk, staging, tex.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, 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_TRANSFER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
@ -437,8 +437,10 @@ struct vk_texture vulkan_create_texture(vk_t *vk,
slock_lock(vk->context->queue_lock); slock_lock(vk->context->queue_lock);
vkQueueSubmit(vk->context->queue, 1, &submit_info, VK_NULL_HANDLE); 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. */ /* 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); vkQueueWaitIdle(vk->context->queue);
slock_unlock(vk->context->queue_lock); slock_unlock(vk->context->queue_lock);
@ -500,7 +502,8 @@ static void vulkan_write_quad_descriptors(VkDevice device,
void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture) void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture)
{ {
/* Transition to GENERAL layout for linear streamed textures. /* Transition to GENERAL layout for linear streamed textures.
* We're using linear textures here, so only GENERAL layout is supported. * We're using linear textures here, so only
* GENERAL layout is supported.
*/ */
if (texture->layout == VK_IMAGE_LAYOUT_PREINITIALIZED) if (texture->layout == VK_IMAGE_LAYOUT_PREINITIALIZED)
{ {
@ -517,7 +520,9 @@ static void vulkan_check_dynamic_state(vk_t *vk)
{ {
if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT) if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT)
{ {
const VkRect2D sci = {{ vk->vp.x, vk->vp.y }, { vk->vp.width, vk->vp.height }}; const VkRect2D sci = {
{ vk->vp.x, vk->vp.y },
{ vk->vp.width, vk->vp.height }};
vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp); vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp);
vkCmdSetScissor(vk->cmd, 0, 1, &sci); vkCmdSetScissor(vk->cmd, 0, 1, &sci);
@ -531,7 +536,8 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call)
if (call->pipeline != vk->tracker.pipeline) if (call->pipeline != vk->tracker.pipeline)
{ {
vkCmdBindPipeline(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, call->pipeline); vkCmdBindPipeline(vk->cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, call->pipeline);
vk->tracker.pipeline = call->pipeline; vk->tracker.pipeline = call->pipeline;
/* Changing pipeline invalidates dynamic state. */ /* Changing pipeline invalidates dynamic state. */
@ -544,9 +550,9 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call)
{ {
VkDescriptorSet set; VkDescriptorSet set;
if (memcmp(call->mvp, &vk->tracker.mvp, sizeof(*call->mvp)) || if (memcmp(call->mvp, &vk->tracker.mvp, sizeof(*call->mvp))
call->texture->view != vk->tracker.view || || (call->texture->view != vk->tracker.view)
call->sampler != vk->tracker.sampler) || (call->sampler != vk->tracker.sampler))
{ {
/* Upload UBO */ /* Upload UBO */
struct vk_buffer_range range; struct vk_buffer_range range;
@ -555,7 +561,8 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call)
return; return;
memcpy(range.data, call->mvp, sizeof(*call->mvp)); memcpy(range.data, call->mvp, sizeof(*call->mvp));
set = vulkan_descriptor_manager_alloc(vk->context->device, &vk->chain->descriptor_manager); set = vulkan_descriptor_manager_alloc(
vk->context->device, &vk->chain->descriptor_manager);
vulkan_write_quad_descriptors(vk->context->device, vulkan_write_quad_descriptors(vk->context->device,
set, set,
range.buffer, range.buffer,
@ -588,7 +595,8 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
if (quad->pipeline != vk->tracker.pipeline) if (quad->pipeline != vk->tracker.pipeline)
{ {
vkCmdBindPipeline(vk->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, quad->pipeline); vkCmdBindPipeline(vk->cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, quad->pipeline);
vk->tracker.pipeline = quad->pipeline; vk->tracker.pipeline = quad->pipeline;
/* Changing pipeline invalidates dynamic state. */ /* Changing pipeline invalidates dynamic state. */
@ -605,9 +613,9 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
sizeof(*quad->mvp), &range)) sizeof(*quad->mvp), &range))
return; return;
if (memcmp(quad->mvp, &vk->tracker.mvp, sizeof(*quad->mvp)) || if (memcmp(quad->mvp, &vk->tracker.mvp, sizeof(*quad->mvp))
quad->texture->view != vk->tracker.view || || quad->texture->view != vk->tracker.view
quad->sampler != vk->tracker.sampler) || quad->sampler != vk->tracker.sampler)
{ {
/* Upload UBO */ /* Upload UBO */
struct vk_buffer_range range; struct vk_buffer_range range;
@ -616,7 +624,9 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
return; return;
memcpy(range.data, quad->mvp, sizeof(*quad->mvp)); memcpy(range.data, quad->mvp, sizeof(*quad->mvp));
set = vulkan_descriptor_manager_alloc(vk->context->device, &vk->chain->descriptor_manager); set = vulkan_descriptor_manager_alloc(vk->context->device,
&vk->chain->descriptor_manager);
vulkan_write_quad_descriptors(vk->context->device, vulkan_write_quad_descriptors(vk->context->device,
set, set,
range.buffer, range.buffer,
@ -655,10 +665,15 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad)
vkCmdDraw(vk->cmd, 6, 1, 0, 0); vkCmdDraw(vk->cmd, 6, 1, 0, 0);
} }
void vulkan_image_layout_transition(vk_t *vk, VkCommandBuffer cmd, VkImage image, void vulkan_image_layout_transition(
VkImageLayout old_layout, VkImageLayout new_layout, vk_t *vk,
VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkCommandBuffer cmd, VkImage image,
VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages) VkImageLayout old_layout,
VkImageLayout new_layout,
VkAccessFlags srcAccess,
VkAccessFlags dstAccess,
VkPipelineStageFlags srcStages,
VkPipelineStageFlags dstStages)
{ {
VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
@ -698,15 +713,18 @@ struct vk_buffer vulkan_create_buffer(const struct vulkan_context *context,
vkGetBufferMemoryRequirements(context->device, buffer.buffer, &mem_reqs); vkGetBufferMemoryRequirements(context->device, buffer.buffer, &mem_reqs);
alloc.allocationSize = mem_reqs.size; alloc.allocationSize = mem_reqs.size;
alloc.memoryTypeIndex = vulkan_find_memory_type(&context->memory_properties, alloc.memoryTypeIndex = vulkan_find_memory_type(
&context->memory_properties,
mem_reqs.memoryTypeBits, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(context->device, &alloc, NULL, &buffer.memory); vkAllocateMemory(context->device, &alloc, NULL, &buffer.memory);
vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0); vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0);
buffer.size = alloc.allocationSize; buffer.size = alloc.allocationSize;
vkMapMemory(context->device, buffer.memory, 0, buffer.size, 0, &buffer.mapped); vkMapMemory(context->device,
buffer.memory, 0, buffer.size, 0, &buffer.mapped);
return buffer; return buffer;
} }
@ -718,14 +736,18 @@ void vulkan_destroy_buffer(VkDevice device, struct vk_buffer *buffer)
memset(buffer, 0, sizeof(*buffer)); memset(buffer, 0, sizeof(*buffer));
} }
static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(VkDevice device, static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(
VkDevice device,
const struct vk_descriptor_manager *manager) const struct vk_descriptor_manager *manager)
{ {
unsigned i; unsigned i;
VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; VkDescriptorPoolCreateInfo pool_info = {
VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_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)); struct vk_descriptor_pool *pool =
(struct vk_descriptor_pool*)calloc(1, sizeof(*pool));
if (!pool) if (!pool)
return NULL; return NULL;
@ -745,7 +767,8 @@ static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(VkDevice device,
return pool; return pool;
} }
VkDescriptorSet vulkan_descriptor_manager_alloc(VkDevice device, struct vk_descriptor_manager *manager) VkDescriptorSet vulkan_descriptor_manager_alloc(
VkDevice device, struct vk_descriptor_manager *manager)
{ {
if (manager->count < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS) if (manager->count < VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS)
return manager->current->sets[manager->count++]; return manager->current->sets[manager->count++];
@ -771,8 +794,11 @@ void vulkan_descriptor_manager_restart(struct vk_descriptor_manager *manager)
manager->count = 0; manager->count = 0;
} }
struct vk_descriptor_manager vulkan_create_descriptor_manager(VkDevice device, struct vk_descriptor_manager vulkan_create_descriptor_manager(
const VkDescriptorPoolSize *sizes, unsigned num_sizes, VkDescriptorSetLayout set_layout) VkDevice device,
const VkDescriptorPoolSize *sizes,
unsigned num_sizes,
VkDescriptorSetLayout set_layout)
{ {
struct vk_descriptor_manager manager; struct vk_descriptor_manager manager;
memset(&manager, 0, sizeof(manager)); memset(&manager, 0, sizeof(manager));
@ -786,7 +812,8 @@ struct vk_descriptor_manager vulkan_create_descriptor_manager(VkDevice device,
return manager; return manager;
} }
void vulkan_destroy_descriptor_manager(VkDevice device, struct vk_descriptor_manager *manager) void vulkan_destroy_descriptor_manager(VkDevice device,
struct vk_descriptor_manager *manager)
{ {
struct vk_descriptor_pool *node = manager->head; struct vk_descriptor_pool *node = manager->head;
@ -794,7 +821,8 @@ void vulkan_destroy_descriptor_manager(VkDevice device, struct vk_descriptor_man
{ {
struct vk_descriptor_pool *next = node->next; struct vk_descriptor_pool *next = node->next;
vkFreeDescriptorSets(device, node->pool, VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS, node->sets); vkFreeDescriptorSets(device, node->pool,
VULKAN_DESCRIPTOR_MANAGER_BLOCK_SETS, node->sets);
vkDestroyDescriptorPool(device, node->pool, NULL); vkDestroyDescriptorPool(device, node->pool, NULL);
free(node); free(node);
@ -810,7 +838,8 @@ static void vulkan_buffer_chain_step(struct vk_buffer_chain *chain)
chain->offset = 0; chain->offset = 0;
} }
static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range) 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; VkDeviceSize next_offset = chain->offset + size;
if (next_offset <= chain->current->buffer.size) if (next_offset <= chain->current->buffer.size)
@ -818,10 +847,12 @@ static bool vulkan_buffer_chain_suballoc(struct vk_buffer_chain *chain, size_t s
range->data = (uint8_t*)chain->current->buffer.mapped + chain->offset; range->data = (uint8_t*)chain->current->buffer.mapped + chain->offset;
range->buffer = chain->current->buffer.buffer; range->buffer = chain->current->buffer.buffer;
range->offset = chain->offset; range->offset = chain->offset;
chain->offset = (next_offset + chain->alignment - 1) & ~(chain->alignment - 1); chain->offset = (next_offset + chain->alignment - 1)
& ~(chain->alignment - 1);
return true; return true;
} }
else
return false; return false;
} }
@ -829,7 +860,8 @@ static struct vk_buffer_node *vulkan_buffer_chain_alloc_node(
const struct vulkan_context *context, const struct vulkan_context *context,
size_t size, VkBufferUsageFlags usage) size_t size, VkBufferUsageFlags usage)
{ {
struct vk_buffer_node *node = (struct vk_buffer_node*)calloc(1, sizeof(*node)); struct vk_buffer_node *node = (struct vk_buffer_node*)
calloc(1, sizeof(*node));
if (!node) if (!node)
return NULL; return NULL;
@ -841,7 +873,8 @@ struct vk_buffer_chain vulkan_buffer_chain_init(VkDeviceSize block_size,
VkDeviceSize alignment, VkDeviceSize alignment,
VkBufferUsageFlags usage) VkBufferUsageFlags usage)
{ {
struct vk_buffer_chain chain = { block_size, alignment, 0, usage, NULL, NULL }; struct vk_buffer_chain chain = {
block_size, alignment, 0, usage, NULL, NULL };
return chain; return chain;
} }
@ -852,7 +885,8 @@ void vulkan_buffer_chain_discard(struct vk_buffer_chain *chain)
} }
bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range) struct vk_buffer_chain *chain,
size_t size, struct vk_buffer_range *range)
{ {
if (!chain->head) if (!chain->head)
{ {
@ -878,7 +912,8 @@ bool vulkan_buffer_chain_alloc(const struct vulkan_context *context,
} }
/* We have to allocate a new node, might allocate larger /* We have to allocate a new node, might allocate larger
* buffer here than block_size in case we have a very large allocation. */ * buffer here than block_size in case we have
* a very large allocation. */
if (size < chain->block_size) if (size < chain->block_size)
size = chain->block_size; size = chain->block_size;

View File

@ -52,11 +52,14 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <gfx/math/matrix_4x4.h> #include <boolean.h>
#include <formats/image.h>
#include <retro_inline.h> #include <retro_inline.h>
#include <retro_miscellaneous.h> #include <retro_miscellaneous.h>
#include "boolean.h" #include <gfx/math/matrix_4x4.h>
#include <gfx/scaler/scaler.h>
#include <rthreads/rthreads.h>
#include <formats/image.h>
#include "../../driver.h" #include "../../driver.h"
#include "../../performance.h" #include "../../performance.h"
#include "../../libretro.h" #include "../../libretro.h"
@ -66,8 +69,6 @@
#include "../video_context_driver.h" #include "../video_context_driver.h"
#include "libretro_vulkan.h" #include "libretro_vulkan.h"
#include "../drivers_shader/shader_vulkan.h" #include "../drivers_shader/shader_vulkan.h"
#include <rthreads/rthreads.h>
#include <gfx/scaler/scaler.h>
enum vk_texture_type enum vk_texture_type
{ {
@ -132,10 +133,14 @@ typedef struct gfx_ctx_vulkan_data
{ {
vulkan_context_t context; vulkan_context_t context;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR; PFN_vkGetPhysicalDeviceSurfaceSupportKHR
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR; fpGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR; fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
fpGetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
fpGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
@ -451,7 +456,8 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad);
*/ */
void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call); 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, void vulkan_image_layout_transition(vk_t *vk,
VkCommandBuffer cmd, VkImage image,
VkImageLayout old_layout, VkImageLayout new_layout, VkImageLayout old_layout, VkImageLayout new_layout,
VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkAccessFlags srcAccess, VkAccessFlags dstAccess,
VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages); VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages);

View File

@ -72,8 +72,10 @@ static const gfx_ctx_driver_t *vulkan_get_context(vk_t *vk)
static void vulkan_init_render_pass(vk_t *vk) static void vulkan_init_render_pass(vk_t *vk)
{ {
VkAttachmentDescription attachment = {0}; VkAttachmentDescription attachment = {0};
VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; VkRenderPassCreateInfo rp_info = {
VkAttachmentReference color_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
VkAttachmentReference color_ref = { 0,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpass = {0}; VkSubpassDescription subpass = {0};
/* Backbuffer format. */ /* Backbuffer format. */
@ -88,7 +90,8 @@ static void vulkan_init_render_pass(vk_t *vk)
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
/* The image layout will be attachment_optimal when we're executing the renderpass. */ /* The image layout will be attachment_optimal
* when we're executing the renderpass. */
attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@ -104,7 +107,8 @@ static void vulkan_init_render_pass(vk_t *vk)
rp_info.subpassCount = 1; rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass; rp_info.pSubpasses = &subpass;
vkCreateRenderPass(vk->context->device, &rp_info, NULL, &vk->render_pass); vkCreateRenderPass(vk->context->device,
&rp_info, NULL, &vk->render_pass);
} }
static void vulkan_init_framebuffers(vk_t *vk) static void vulkan_init_framebuffers(vk_t *vk)
@ -114,8 +118,10 @@ static void vulkan_init_framebuffers(vk_t *vk)
for (i = 0; i < vk->num_swapchain_images; i++) for (i = 0; i < vk->num_swapchain_images; i++)
{ {
VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo view = {
VkFramebufferCreateInfo info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; 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]; vk->swapchain[i].backbuffer.image = vk->context->swapchain_images[i];
@ -151,8 +157,10 @@ static void vulkan_init_framebuffers(vk_t *vk)
static void vulkan_init_pipeline_layout(vk_t *vk) static void vulkan_init_pipeline_layout(vk_t *vk)
{ {
VkDescriptorSetLayoutCreateInfo set_layout_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; VkDescriptorSetLayoutCreateInfo set_layout_info = {
VkPipelineLayoutCreateInfo layout_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
VkPipelineLayoutCreateInfo layout_info = {
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
VkDescriptorSetLayoutBinding bindings[2] = {{0}}; VkDescriptorSetLayoutBinding bindings[2] = {{0}};
bindings[0].binding = 0; bindings[0].binding = 0;
@ -170,34 +178,46 @@ static void vulkan_init_pipeline_layout(vk_t *vk)
set_layout_info.bindingCount = 2; set_layout_info.bindingCount = 2;
set_layout_info.pBindings = bindings; set_layout_info.pBindings = bindings;
vkCreateDescriptorSetLayout(vk->context->device, &set_layout_info, NULL, &vk->pipelines.set_layout); vkCreateDescriptorSetLayout(vk->context->device,
&set_layout_info, NULL, &vk->pipelines.set_layout);
layout_info.setLayoutCount = 1; layout_info.setLayoutCount = 1;
layout_info.pSetLayouts = &vk->pipelines.set_layout; layout_info.pSetLayouts = &vk->pipelines.set_layout;
vkCreatePipelineLayout(vk->context->device, &layout_info, NULL, &vk->pipelines.layout); vkCreatePipelineLayout(vk->context->device,
&layout_info, NULL, &vk->pipelines.layout);
} }
static void vulkan_init_pipelines(vk_t *vk) static void vulkan_init_pipelines(vk_t *vk)
{ {
unsigned i; unsigned i;
VkPipelineInputAssemblyStateCreateInfo input_assembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; VkPipelineInputAssemblyStateCreateInfo input_assembly = {
VkPipelineVertexInputStateCreateInfo vertex_input = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_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}; VkPipelineColorBlendAttachmentState blend_attachment = {0};
VkPipelineColorBlendStateCreateInfo blend = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VkPipelineColorBlendStateCreateInfo blend = {
VkPipelineViewportStateCreateInfo viewport = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
VkPipelineDepthStencilStateCreateInfo depth_stencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; VkPipelineViewportStateCreateInfo viewport = {
VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
VkPipelineDynamicStateCreateInfo dynamic = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_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] = { VkPipelineShaderStageCreateInfo shader_stages[2] = {
{ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO },
{ 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 }; VkGraphicsPipelineCreateInfo pipe = {
VkShaderModuleCreateInfo module_info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
VkShaderModuleCreateInfo module_info = {
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
VkVertexInputAttributeDescription attributes[3] = {{0}}; VkVertexInputAttributeDescription attributes[3] = {{0}};
VkVertexInputBindingDescription binding = {0}; VkVertexInputBindingDescription binding = {0};
@ -286,12 +306,15 @@ static void vulkan_init_pipelines(vk_t *vk)
module_info.pCode = (const uint32_t*)alpha_blend_vert_spv; module_info.pCode = (const uint32_t*)alpha_blend_vert_spv;
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
shader_stages[0].pName = "main"; shader_stages[0].pName = "main";
vkCreateShaderModule(vk->context->device, &module_info, NULL, &shader_stages[0].module); vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[0].module);
module_info.codeSize = alpha_blend_frag_spv_len; module_info.codeSize = alpha_blend_frag_spv_len;
module_info.pCode = (const uint32_t*)alpha_blend_frag_spv; module_info.pCode = (const uint32_t*)alpha_blend_frag_spv;
shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
shader_stages[1].pName = "main"; shader_stages[1].pName = "main";
vkCreateShaderModule(vk->context->device, &module_info, NULL, &shader_stages[1].module); vkCreateShaderModule(vk->context->device,
&module_info, NULL, &shader_stages[1].module);
blend_attachment.blendEnable = true; blend_attachment.blendEnable = true;
blend_attachment.colorWriteMask = 0xf; blend_attachment.colorWriteMask = 0xf;
@ -326,17 +349,22 @@ static void vulkan_init_command_buffers(vk_t *vk)
unsigned i; unsigned i;
for (i = 0; i < vk->num_swapchain_images; i++) for (i = 0; i < vk->num_swapchain_images; i++)
{ {
VkCommandPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; VkCommandPoolCreateInfo pool_info = {
VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_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.queueFamilyIndex = vk->context->graphics_queue_index;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; pool_info.flags =
vkCreateCommandPool(vk->context->device, &pool_info, NULL, &vk->swapchain[i].cmd_pool); 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.commandPool = vk->swapchain[i].cmd_pool;
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
info.commandBufferCount = 1; info.commandBufferCount = 1;
vkAllocateCommandBuffers(vk->context->device, &info, &vk->swapchain[i].cmd); vkAllocateCommandBuffers(vk->context->device,
&info, &vk->swapchain[i].cmd);
} }
} }
@ -356,8 +384,8 @@ static void vulkan_init_samplers(vk_t *vk)
info.maxLod = 0.0f; info.maxLod = 0.0f;
info.unnormalizedCoordinates = false; info.unnormalizedCoordinates = false;
info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.nearest); vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.nearest);
info.magFilter = VK_FILTER_LINEAR; info.magFilter = VK_FILTER_LINEAR;
info.minFilter = VK_FILTER_LINEAR; info.minFilter = VK_FILTER_LINEAR;
vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.linear); vkCreateSampler(vk->context->device, &info, NULL, &vk->samplers.linear);
@ -396,7 +424,8 @@ static void vulkan_deinit_buffers(vk_t *vk)
static void vulkan_init_descriptor_pool(vk_t *vk) static void vulkan_init_descriptor_pool(vk_t *vk)
{ {
unsigned i; unsigned i;
VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; VkDescriptorPoolCreateInfo pool_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
static const VkDescriptorPoolSize pool_sizes[2] = { static const VkDescriptorPoolSize pool_sizes[2] = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 },
@ -404,7 +433,8 @@ static void vulkan_init_descriptor_pool(vk_t *vk)
for (i = 0; i < vk->num_swapchain_images; i++) for (i = 0; i < vk->num_swapchain_images; i++)
{ {
vk->swapchain[i].descriptor_manager = vulkan_create_descriptor_manager(vk->context->device, vk->swapchain[i].descriptor_manager =
vulkan_create_descriptor_manager(vk->context->device,
pool_sizes, 2, vk->pipelines.set_layout); pool_sizes, 2, vk->pipelines.set_layout);
} }
} }
@ -413,7 +443,8 @@ static void vulkan_deinit_descriptor_pool(vk_t *vk)
{ {
unsigned i; unsigned i;
for (i = 0; i < vk->num_swapchain_images; i++) for (i = 0; i < vk->num_swapchain_images; i++)
vulkan_destroy_descriptor_manager(vk->context->device, &vk->swapchain[i].descriptor_manager); vulkan_destroy_descriptor_manager(vk->context->device,
&vk->swapchain[i].descriptor_manager);
} }
static void vulkan_init_textures(vk_t *vk) static void vulkan_init_textures(vk_t *vk)
@ -426,7 +457,8 @@ static void vulkan_init_textures(vk_t *vk)
for (i = 0; i < vk->num_swapchain_images; i++) for (i = 0; i < vk->num_swapchain_images; i++)
{ {
vk->swapchain[i].texture = vulkan_create_texture(vk, NULL, vk->swapchain[i].texture = vulkan_create_texture(vk, NULL,
vk->tex_w, vk->tex_h, vk->tex_fmt, NULL, NULL, VULKAN_TEXTURE_STREAMED); vk->tex_w, vk->tex_h, vk->tex_fmt,
NULL, NULL, VULKAN_TEXTURE_STREAMED);
vulkan_map_persistent_texture(vk->context->device, vulkan_map_persistent_texture(vk->context->device,
&vk->swapchain[i].texture); &vk->swapchain[i].texture);
@ -463,14 +495,17 @@ static void vulkan_deinit_command_buffers(vk_t *vk)
vkFreeCommandBuffers(vk->context->device, vkFreeCommandBuffers(vk->context->device,
vk->swapchain[i].cmd_pool, 1, &vk->swapchain[i].cmd); vk->swapchain[i].cmd_pool, 1, &vk->swapchain[i].cmd);
vkDestroyCommandPool(vk->context->device, vk->swapchain[i].cmd_pool, NULL); vkDestroyCommandPool(vk->context->device,
vk->swapchain[i].cmd_pool, NULL);
} }
} }
static void vulkan_deinit_pipeline_layout(vk_t *vk) static void vulkan_deinit_pipeline_layout(vk_t *vk)
{ {
vkDestroyPipelineLayout(vk->context->device, vk->pipelines.layout, NULL); vkDestroyPipelineLayout(vk->context->device,
vkDestroyDescriptorSetLayout(vk->context->device, vk->pipelines.set_layout, NULL); vk->pipelines.layout, NULL);
vkDestroyDescriptorSetLayout(vk->context->device,
vk->pipelines.set_layout, NULL);
} }
static void vulkan_deinit_pipelines(vk_t *vk) static void vulkan_deinit_pipelines(vk_t *vk)
@ -511,7 +546,10 @@ static bool vulkan_init_default_filter_chain(vk_t *vk)
info.swapchain.render_pass = vk->render_pass; info.swapchain.render_pass = vk->render_pass;
info.swapchain.num_indices = vk->context->num_swapchain_images; 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); vk->filter_chain = vulkan_filter_chain_create_default(&info,
vk->video.smooth ?
VULKAN_FILTER_CHAIN_LINEAR : VULKAN_FILTER_CHAIN_NEAREST);
if (!vk->filter_chain) if (!vk->filter_chain)
{ {
RARCH_ERR("Failed to create filter chain.\n"); RARCH_ERR("Failed to create filter chain.\n");
@ -589,36 +627,44 @@ static void vulkan_init_resources(vk_t *vk)
static void vulkan_init_static_resources(vk_t *vk) static void vulkan_init_static_resources(vk_t *vk)
{ {
VkCommandPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
unsigned i; unsigned i;
uint32_t blank[4 * 4]; uint32_t blank[4 * 4];
VkCommandPoolCreateInfo pool_info = {
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
/* Create the pipeline cache. */ /* Create the pipeline cache. */
VkPipelineCacheCreateInfo cache = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkPipelineCacheCreateInfo cache = {
vkCreatePipelineCache(vk->context->device, &cache, NULL, &vk->pipelines.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; pool_info.queueFamilyIndex = vk->context->graphics_queue_index;
vkCreateCommandPool(vk->context->device, &pool_info, NULL, &vk->staging_pool); vkCreateCommandPool(vk->context->device,
&pool_info, NULL, &vk->staging_pool);
for (i = 0; i < 4 * 4; i++) for (i = 0; i < 4 * 4; i++)
blank[i] = -1u; blank[i] = -1u;
vk->display.blank_texture = vulkan_create_texture(vk, NULL, vk->display.blank_texture = vulkan_create_texture(vk, NULL,
4, 4, VK_FORMAT_B8G8R8A8_UNORM, blank, NULL, VULKAN_TEXTURE_STATIC); 4, 4, VK_FORMAT_B8G8R8A8_UNORM,
blank, NULL, VULKAN_TEXTURE_STATIC);
} }
static void vulkan_deinit_static_resources(vk_t *vk) static void vulkan_deinit_static_resources(vk_t *vk)
{ {
unsigned i; unsigned i;
vkDestroyPipelineCache(vk->context->device, vk->pipelines.cache, NULL); vkDestroyPipelineCache(vk->context->device,
vulkan_destroy_texture(vk->context->device, &vk->display.blank_texture); vk->pipelines.cache, NULL);
vulkan_destroy_texture(vk->context->device,
&vk->display.blank_texture);
vkDestroyCommandPool(vk->context->device, vk->staging_pool, NULL); vkDestroyCommandPool(vk->context->device, vk->staging_pool, NULL);
free(vk->hw.cmd); free(vk->hw.cmd);
free(vk->hw.wait_dst_stages); free(vk->hw.wait_dst_stages);
for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++) for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++)
if (vk->readback.staging[i].memory != VK_NULL_HANDLE) if (vk->readback.staging[i].memory != VK_NULL_HANDLE)
vulkan_destroy_texture(vk->context->device, &vk->readback.staging[i]); vulkan_destroy_texture(vk->context->device,
&vk->readback.staging[i]);
} }
static void vulkan_deinit_resources(vk_t *vk) static void vulkan_deinit_resources(vk_t *vk)
@ -688,8 +734,8 @@ static void vulkan_set_image(void *handle,
uint32_t num_semaphores, uint32_t num_semaphores,
const VkSemaphore *semaphores) const VkSemaphore *semaphores)
{ {
vk_t *vk = (vk_t*)handle;
unsigned i; unsigned i;
vk_t *vk = (vk_t*)handle;
vk->hw.image = image; vk->hw.image = image;
vk->hw.num_semaphores = num_semaphores; vk->hw.num_semaphores = num_semaphores;
@ -697,9 +743,12 @@ static void vulkan_set_image(void *handle,
if (num_semaphores > 0) if (num_semaphores > 0)
{ {
vk->hw.wait_dst_stages = (VkPipelineStageFlags*)realloc(vk->hw.wait_dst_stages, vk->hw.wait_dst_stages = (VkPipelineStageFlags*)
realloc(vk->hw.wait_dst_stages,
sizeof(VkPipelineStageFlags) * vk->hw.num_semaphores); sizeof(VkPipelineStageFlags) * vk->hw.num_semaphores);
retro_assert(vk->hw.wait_dst_stages); /* If this fails, we're screwed anyways. */
/* If this fails, we're screwed anyways. */
retro_assert(vk->hw.wait_dst_stages);
for (i = 0; i < vk->hw.num_semaphores; i++) for (i = 0; i < vk->hw.num_semaphores; i++)
vk->hw.wait_dst_stages[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; vk->hw.wait_dst_stages[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
@ -722,7 +771,9 @@ static void vulkan_set_command_buffers(void *handle, uint32_t num_cmd,
{ {
vk->hw.cmd = (VkCommandBuffer*)realloc(vk->hw.cmd, vk->hw.cmd = (VkCommandBuffer*)realloc(vk->hw.cmd,
sizeof(VkCommandBuffer) * required_capacity); sizeof(VkCommandBuffer) * required_capacity);
retro_assert(vk->hw.cmd); /* If this fails, we're just screwed. */
/* If this fails, we're just screwed. */
retro_assert(vk->hw.cmd);
vk->hw.capacity_cmd = required_capacity; vk->hw.capacity_cmd = required_capacity;
} }
@ -805,13 +856,15 @@ static void vulkan_init_readback(vk_t *vk)
static void *vulkan_init(const video_info_t *video, const input_driver_t **input, static void *vulkan_init(const video_info_t *video, const input_driver_t **input,
void **input_data) 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_mode_t mode;
gfx_ctx_input_t inp; gfx_ctx_input_t inp;
unsigned interval; unsigned interval;
unsigned win_width;
unsigned win_height;
unsigned temp_width = 0;
unsigned temp_height = 0;
const gfx_ctx_driver_t *ctx_driver = NULL;
settings_t *settings = config_get_ptr();
vk_t *vk = (vk_t*)calloc(1, sizeof(*vk)); vk_t *vk = (vk_t*)calloc(1, sizeof(*vk));
if (!vk) if (!vk)
return NULL; return NULL;
@ -867,8 +920,10 @@ static void *vulkan_init(const video_info_t *video, const input_driver_t **input
vk->vsync = video->vsync; vk->vsync = video->vsync;
vk->fullscreen = video->fullscreen; vk->fullscreen = video->fullscreen;
vk->tex_w = vk->tex_h = RARCH_SCALE_BASE * video->input_scale; vk->tex_w = RARCH_SCALE_BASE * video->input_scale;
vk->tex_fmt = video->rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R5G6B5_UNORM_PACK16; 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; vk->keep_aspect = video->force_aspect;
/* Set the viewport to fix recording, since it needs to know /* Set the viewport to fix recording, since it needs to know
@ -931,9 +986,9 @@ static void vulkan_check_swapchain(vk_t *vk)
static void vulkan_set_nonblock_state(void *data, bool state) static void vulkan_set_nonblock_state(void *data, bool state)
{ {
unsigned interval;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
unsigned interval;
if (!vk) if (!vk)
return; return;
@ -951,9 +1006,11 @@ static void vulkan_set_nonblock_state(void *data, bool state)
static bool vulkan_alive(void *data) static bool vulkan_alive(void *data)
{ {
gfx_ctx_size_t size_data; gfx_ctx_size_t size_data;
unsigned temp_width = 0, temp_height = 0; unsigned temp_width = 0;
unsigned temp_height = 0;
bool ret = false; bool ret = false;
bool quit = false, resize = false; bool quit = false;
bool resize = false;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
video_driver_get_size(&temp_width, &temp_height); video_driver_get_size(&temp_width, &temp_height);
@ -998,7 +1055,8 @@ static bool vulkan_has_windowed(void *data)
return gfx_ctx_ctl(GFX_CTL_HAS_WINDOWED, NULL); return gfx_ctx_ctl(GFX_CTL_HAS_WINDOWED, NULL);
} }
static bool vulkan_set_shader(void *data, enum rarch_shader_type type, const char *path) static bool vulkan_set_shader(void *data,
enum rarch_shader_type type, const char *path)
{ {
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
if (!vk) if (!vk)
@ -1030,7 +1088,8 @@ static bool vulkan_set_shader(void *data, enum rarch_shader_type type, const cha
return true; return true;
} }
static void vulkan_set_projection(vk_t *vk, struct gfx_ortho *ortho, bool allow_rotate) static void vulkan_set_projection(vk_t *vk,
struct gfx_ortho *ortho, bool allow_rotate)
{ {
math_matrix_4x4 rot; math_matrix_4x4 rot;
@ -1060,7 +1119,8 @@ static void vulkan_set_rotation(void *data, unsigned rotation)
vulkan_set_projection(vk, &ortho, true); vulkan_set_projection(vk, &ortho, true);
} }
static void vulkan_set_video_mode(void *data, unsigned width, unsigned height, static void vulkan_set_video_mode(void *data,
unsigned width, unsigned height,
bool fullscreen) bool fullscreen)
{ {
(void)data; (void)data;
@ -1078,7 +1138,8 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
{ {
gfx_ctx_aspect_t aspect_data; gfx_ctx_aspect_t aspect_data;
unsigned width, height; unsigned width, height;
int x = 0, y = 0; int x = 0;
int y = 0;
float device_aspect = (float)viewport_width / viewport_height; float device_aspect = (float)viewport_width / viewport_height;
struct gfx_ortho ortho = {0, 1, 0, 1, -1, 1}; struct gfx_ortho ortho = {0, 1, 0, 1, -1, 1};
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
@ -1129,13 +1190,15 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
} }
else if (device_aspect > desired_aspect) else if (device_aspect > desired_aspect)
{ {
delta = (desired_aspect / device_aspect - 1.0f) / 2.0f + 0.5f; delta = (desired_aspect / device_aspect - 1.0f)
/ 2.0f + 0.5f;
x = (int)roundf(viewport_width * (0.5f - delta)); x = (int)roundf(viewport_width * (0.5f - delta));
viewport_width = (unsigned)roundf(2.0f * viewport_width * delta); viewport_width = (unsigned)roundf(2.0f * viewport_width * delta);
} }
else else
{ {
delta = (device_aspect / desired_aspect - 1.0f) / 2.0f + 0.5f; delta = (device_aspect / desired_aspect - 1.0f)
/ 2.0f + 0.5f;
y = (int)roundf(viewport_height * (0.5f - delta)); y = (int)roundf(viewport_height * (0.5f - delta));
viewport_height = (unsigned)roundf(2.0f * viewport_height * delta); viewport_height = (unsigned)roundf(2.0f * viewport_height * delta);
} }
@ -1148,7 +1211,8 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
} }
else else
{ {
vk->vp.x = vk->vp.y = 0; vk->vp.x = 0;
vk->vp.y = 0;
vk->vp.width = viewport_width; vk->vp.width = viewport_width;
vk->vp.height = viewport_height; vk->vp.height = viewport_height;
} }
@ -1238,19 +1302,23 @@ static bool vulkan_frame(void *data, const void *frame,
uint64_t frame_count, uint64_t frame_count,
unsigned pitch, const char *msg) unsigned pitch, const char *msg)
{ {
struct vk_per_frame *chain;
unsigned width, height;
VkClearValue clear_value;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
static struct retro_perf_counter frame_run = {0}; static struct retro_perf_counter frame_run = {0};
static struct retro_perf_counter copy_frame = {0}; static struct retro_perf_counter copy_frame = {0};
static struct retro_perf_counter swapbuffers = {0}; static struct retro_perf_counter swapbuffers = {0};
static struct retro_perf_counter queue_submit = {0}; static struct retro_perf_counter queue_submit = {0};
struct vk_per_frame *chain; VkCommandBufferBeginInfo begin_info = {
unsigned width, height; VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
VkClearValue clear_value; VkRenderPassBeginInfo rp_info = {
VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
VkRenderPassBeginInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; VkSubmitInfo submit_info = {
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; VK_STRUCTURE_TYPE_SUBMIT_INFO };
unsigned frame_index = vk->context->current_swapchain_index; unsigned frame_index =
vk->context->current_swapchain_index;
rarch_perf_init(&frame_run, "frame_run"); rarch_perf_init(&frame_run, "frame_run");
rarch_perf_init(&copy_frame, "copy_frame"); rarch_perf_init(&copy_frame, "copy_frame");
@ -1284,7 +1352,8 @@ static bool vulkan_frame(void *data, const void *frame,
const uint8_t *src = (const uint8_t*)frame; const uint8_t *src = (const uint8_t*)frame;
unsigned bpp = vk->video.rgb32 ? 4 : 2; unsigned bpp = vk->video.rgb32 ? 4 : 2;
if (chain->texture.width != frame_width || chain->texture.height != frame_height) if ( chain->texture.width != frame_width
|| chain->texture.height != frame_height)
{ {
chain->texture = vulkan_create_texture(vk, &chain->texture, chain->texture = vulkan_create_texture(vk, &chain->texture,
frame_width, frame_height, chain->texture.format, NULL, NULL, frame_width, frame_height, chain->texture.format, NULL, NULL,
@ -1305,7 +1374,8 @@ static bool vulkan_frame(void *data, const void *frame,
if (chain->texture.stride == pitch && pitch == frame_width * bpp) if (chain->texture.stride == pitch && pitch == frame_width * bpp)
memcpy(dst, src, frame_width * frame_height * bpp); memcpy(dst, src, frame_width * frame_height * bpp);
else else
for (y = 0; y < frame_height; y++, dst += chain->texture.stride, src += pitch) for (y = 0; y < frame_height; y++,
dst += chain->texture.stride, src += pitch)
memcpy(dst, src, frame_width * bpp); memcpy(dst, src, frame_width * bpp);
} }
@ -1373,7 +1443,8 @@ static bool vulkan_frame(void *data, const void *frame,
vulkan_set_viewport(vk, width, height, false, true); vulkan_set_viewport(vk, width, height, false, true);
vulkan_filter_chain_build_offscreen_passes(vk->filter_chain, vk->cmd, &vk->vk_vp); vulkan_filter_chain_build_offscreen_passes(
vk->filter_chain, vk->cmd, &vk->vk_vp);
/* Render to backbuffer. */ /* Render to backbuffer. */
clear_value.color.float32[0] = 0.0f; clear_value.color.float32[0] = 0.0f;
@ -1450,32 +1521,46 @@ static bool vulkan_frame(void *data, const void *frame,
if (vk->readback.pending || vk->readback.streamed) if (vk->readback.pending || vk->readback.streamed)
{ {
/* We cannot safely read back from an image which has already been presented /* We cannot safely read back from an image which
* as we need to maintain the PRESENT_SRC_KHR layout. * has already been presented as we need to
* maintain the PRESENT_SRC_KHR layout.
*
* If we're reading back, perform the readback before presenting. * If we're reading back, perform the readback before presenting.
*/ */
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, vulkan_image_layout_transition(vk,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk->cmd, chain->backbuffer.image,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); 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); vulkan_readback(vk);
/* Prepare for presentation after transfers are complete. */ /* Prepare for presentation after transfers are complete. */
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, vulkan_image_layout_transition(vk, vk->cmd,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, chain->backbuffer.image,
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); 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; vk->readback.pending = false;
} }
else else
{ {
/* Prepare backbuffer for presentation. */ /* Prepare backbuffer for presentation. */
vulkan_image_layout_transition(vk, vk->cmd, chain->backbuffer.image, vulkan_image_layout_transition(vk, vk->cmd,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, chain->backbuffer.image,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); 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); vkEndCommandBuffer(vk->cmd);
@ -1505,14 +1590,18 @@ static bool vulkan_frame(void *data, const void *frame,
submit_info.pWaitDstStageMask = vk->hw.wait_dst_stages; submit_info.pWaitDstStageMask = vk->hw.wait_dst_stages;
} }
submit_info.signalSemaphoreCount = vk->context->swapchain_semaphores[frame_index] != VK_NULL_HANDLE ? 1 : 0; submit_info.signalSemaphoreCount =
submit_info.pSignalSemaphores = &vk->context->swapchain_semaphores[frame_index]; 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_stop(&frame_run);
retro_perf_start(&queue_submit); retro_perf_start(&queue_submit);
slock_lock(vk->context->queue_lock); slock_lock(vk->context->queue_lock);
vkQueueSubmit(vk->context->queue, 1, &submit_info, vk->context->swapchain_fences[frame_index]); vkQueueSubmit(vk->context->queue, 1,
&submit_info, vk->context->swapchain_fences[frame_index]);
slock_unlock(vk->context->queue_lock); slock_unlock(vk->context->queue_lock);
retro_perf_stop(&queue_submit); retro_perf_stop(&queue_submit);
@ -1564,7 +1653,8 @@ static void vulkan_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
if (cmd != RARCH_DISPLAY_CTL_NONE) if (cmd != RARCH_DISPLAY_CTL_NONE)
video_driver_ctl(cmd, NULL); video_driver_ctl(cmd, NULL);
video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value); video_driver_set_aspect_ratio_value(
aspectratio_lut[aspect_ratio_idx].value);
if (!vk) if (!vk)
return; return;
@ -1595,10 +1685,11 @@ static struct video_shader *vulkan_get_current_shader(void *data)
return vulkan_filter_chain_get_preset(vk->filter_chain); return vulkan_filter_chain_get_preset(vk->filter_chain);
} }
static bool vulkan_get_current_sw_framebuffer(void *data, struct retro_framebuffer *framebuffer) static bool vulkan_get_current_sw_framebuffer(void *data,
struct retro_framebuffer *framebuffer)
{ {
vk_t *vk = (vk_t*)data;
struct vk_per_frame *chain; struct vk_per_frame *chain;
vk_t *vk = (vk_t*)data;
vk->chain = &vk->swapchain[vk->context->current_swapchain_index]; vk->chain = &vk->swapchain[vk->context->current_swapchain_index];
chain = vk->chain; chain = vk->chain;
@ -1620,10 +1711,12 @@ static bool vulkan_get_current_sw_framebuffer(void *data, struct retro_framebuff
framebuffer->data = chain->texture.mapped; framebuffer->data = chain->texture.mapped;
framebuffer->pitch = chain->texture.stride; framebuffer->pitch = chain->texture.stride;
framebuffer->format = vk->video.rgb32 ? RETRO_PIXEL_FORMAT_XRGB8888 : RETRO_PIXEL_FORMAT_RGB565; framebuffer->format = vk->video.rgb32
? RETRO_PIXEL_FORMAT_XRGB8888 : RETRO_PIXEL_FORMAT_RGB565;
framebuffer->memory_flags = 0; framebuffer->memory_flags = 0;
if (vk->context->memory_properties.memoryTypes[chain->texture.memory_type].propertyFlags & if (vk->context->memory_properties.memoryTypes[
chain->texture.memory_type].propertyFlags &
VK_MEMORY_PROPERTY_HOST_CACHED_BIT) VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
{ {
framebuffer->memory_flags |= RETRO_MEMORY_TYPE_CACHED; framebuffer->memory_flags |= RETRO_MEMORY_TYPE_CACHED;
@ -1632,7 +1725,8 @@ static bool vulkan_get_current_sw_framebuffer(void *data, struct retro_framebuff
return true; return true;
} }
static bool vulkan_get_hw_render_interface(void *data, const struct retro_hw_render_interface **iface) static bool vulkan_get_hw_render_interface(void *data,
const struct retro_hw_render_interface **iface)
{ {
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
*iface = (const struct retro_hw_render_interface*)&vk->hw.iface; *iface = (const struct retro_hw_render_interface*)&vk->hw.iface;
@ -1644,13 +1738,12 @@ static void vulkan_set_texture_frame(void *data,
const void *frame, bool rgb32, unsigned width, unsigned height, const void *frame, bool rgb32, unsigned width, unsigned height,
float alpha) float alpha)
{ {
uint8_t *ptr;
unsigned x, y;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
unsigned index = vk->context->current_swapchain_index; unsigned index = vk->context->current_swapchain_index;
struct vk_texture *texture = &vk->menu.textures[index]; struct vk_texture *texture = &vk->menu.textures[index];
struct vk_texture *texture_optimal = &vk->menu.textures_optimal[index]; struct vk_texture *texture_optimal = &vk->menu.textures_optimal[index];
uint8_t *ptr;
unsigned x, y;
const VkComponentMapping br_swizzle = { const VkComponentMapping br_swizzle = {
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G,
@ -1719,8 +1812,6 @@ static uintptr_t vulkan_load_texture(void *video_data, void *data,
{ {
vk_t *vk = (vk_t*)video_data; vk_t *vk = (vk_t*)video_data;
struct texture_image *image = (struct texture_image*)data; struct texture_image *image = (struct texture_image*)data;
(void)threaded; /* Pfft. */
struct vk_texture *texture = (struct vk_texture*)calloc(1, sizeof(*texture)); struct vk_texture *texture = (struct vk_texture*)calloc(1, sizeof(*texture));
if (!texture) if (!texture)
return 0; return 0;
@ -1787,8 +1878,8 @@ static void vulkan_get_poke_interface(void *data,
static void vulkan_viewport_info(void *data, struct video_viewport *vp) static void vulkan_viewport_info(void *data, struct video_viewport *vp)
{ {
vk_t *vk = (vk_t*)data;
unsigned width, height; unsigned width, height;
vk_t *vk = (vk_t*)data;
video_driver_get_size(&width, &height); video_driver_get_size(&width, &height);
@ -1851,7 +1942,8 @@ static bool vulkan_read_viewport(void *data, uint8_t *buffer)
{ {
unsigned x, y; unsigned x, y;
const uint8_t *src = (const uint8_t*)staging->mapped; const uint8_t *src = (const uint8_t*)staging->mapped;
buffer += 3 * (vk->vp.height - 1) * vk->vp.width; buffer += 3 * (vk->vp.height - 1)
* vk->vp.width;
for (y = 0; y < vk->vp.height; y++, for (y = 0; y < vk->vp.height; y++,
src += staging->stride, buffer -= 3 * vk->vp.width) src += staging->stride, buffer -= 3 * vk->vp.width)
@ -1899,16 +1991,18 @@ static void vulkan_overlay_free(vk_t *vk)
free(vk->overlay.vertex); free(vk->overlay.vertex);
for (i = 0; i < vk->overlay.count; i++) for (i = 0; i < vk->overlay.count; i++)
if (vk->overlay.images[i].memory != VK_NULL_HANDLE) if (vk->overlay.images[i].memory != VK_NULL_HANDLE)
vulkan_destroy_texture(vk->context->device, &vk->overlay.images[i]); vulkan_destroy_texture(vk->context->device,
&vk->overlay.images[i]);
memset(&vk->overlay, 0, sizeof(vk->overlay)); memset(&vk->overlay, 0, sizeof(vk->overlay));
} }
static void vulkan_overlay_set_alpha(void *data, unsigned image, float mod) static void vulkan_overlay_set_alpha(void *data,
unsigned image, float mod)
{ {
vk_t *vk = (vk_t*)data;
struct vk_vertex *pv;
unsigned i; unsigned i;
struct vk_vertex *pv;
vk_t *vk = (vk_t*)data;
if (!vk) if (!vk)
return; return;
@ -1944,7 +2038,8 @@ static void vulkan_render_overlay(vk_t *vk)
4 * sizeof(struct vk_vertex), &range)) 4 * sizeof(struct vk_vertex), &range))
break; break;
memcpy(range.data, &vk->overlay.vertex[i * 4], 4 * sizeof(struct vk_vertex)); memcpy(range.data, &vk->overlay.vertex[i * 4],
4 * sizeof(struct vk_vertex));
memset(&call, 0, sizeof(call)); memset(&call, 0, sizeof(call));
call.pipeline = vk->display.pipelines[3]; /* Strip with blend */ call.pipeline = vk->display.pipelines[3]; /* Strip with blend */
@ -1964,11 +2059,13 @@ static void vulkan_overlay_vertex_geom(void *data, unsigned image,
float x, float y, float x, float y,
float w, float h) float w, float h)
{ {
struct vk_vertex *pv = NULL;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
if (!vk) if (!vk)
return; return;
struct vk_vertex *pv = &vk->overlay.vertex[4 * image]; pv = &vk->overlay.vertex[4 * image];
pv[0].x = x; pv[0].x = x;
pv[0].y = y; pv[0].y = y;
pv[1].x = x; pv[1].x = x;
@ -1983,11 +2080,13 @@ static void vulkan_overlay_tex_geom(void *data, unsigned image,
float x, float y, float x, float y,
float w, float h) float w, float h)
{ {
struct vk_vertex *pv = NULL;
vk_t *vk = (vk_t*)data; vk_t *vk = (vk_t*)data;
if (!vk) if (!vk)
return; return;
struct vk_vertex *pv = &vk->overlay.vertex[4 * image]; pv = &vk->overlay.vertex[4 * image];
pv[0].tex_x = x; pv[0].tex_x = x;
pv[0].tex_y = y; pv[0].tex_y = y;
pv[1].tex_x = x; pv[1].tex_x = x;
@ -2001,9 +2100,10 @@ static void vulkan_overlay_tex_geom(void *data, unsigned image,
static bool vulkan_overlay_load(void *data, static bool vulkan_overlay_load(void *data,
const void *image_data, unsigned num_images) 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; unsigned i, j;
const struct texture_image *images =
(const struct texture_image*)image_data;
vk_t *vk = (vk_t*)data;
static const struct vk_color white = { static const struct vk_color white = {
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
}; };
@ -2016,12 +2116,15 @@ static bool vulkan_overlay_load(void *data,
slock_unlock(vk->context->queue_lock); slock_unlock(vk->context->queue_lock);
vulkan_overlay_free(vk); vulkan_overlay_free(vk);
vk->overlay.images = (struct vk_texture*)calloc(num_images, sizeof(*vk->overlay.images)); vk->overlay.images = (struct vk_texture*)
calloc(num_images, sizeof(*vk->overlay.images));
if (!vk->overlay.images) if (!vk->overlay.images)
goto error; goto error;
vk->overlay.count = num_images; vk->overlay.count = num_images;
vk->overlay.vertex = (struct vk_vertex*)calloc(4 * num_images, sizeof(*vk->overlay.vertex)); vk->overlay.vertex = (struct vk_vertex*)
calloc(4 * num_images, sizeof(*vk->overlay.vertex));
if (!vk->overlay.vertex) if (!vk->overlay.vertex)
goto error; goto error;

View File

@ -801,21 +801,23 @@ static bool gfx_ctx_x_bind_api(void *data, enum gfx_ctx_api api,
g_major = major; g_major = major;
g_minor = minor; g_minor = minor;
g_api = api;
#ifdef HAVE_VULKAN switch (api)
if (api == GFX_CTX_VULKAN_API)
{ {
g_api = api; case GFX_CTX_OPENGL_API:
#ifdef HAVE_OPENGL
g_api = GFX_CTX_OPENGL_API;
return true; return true;
} #else
break;
#endif #endif
case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_OPENGLES2 #ifdef HAVE_OPENGLES2
{
Display *dpy = XOpenDisplay(NULL); Display *dpy = XOpenDisplay(NULL);
const char *exts = glXQueryExtensionsString(dpy, DefaultScreen(dpy)); const char *exts = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
bool ret = api == GFX_CTX_OPENGL_ES_API && bool ret = exts && strstr(exts,
exts && strstr(exts, "GLX_EXT_create_context_es2_profile"); "GLX_EXT_create_context_es2_profile");
XCloseDisplay(dpy); XCloseDisplay(dpy);
if (ret && g_major < 3) if (ret && g_major < 3)
{ {
@ -824,10 +826,23 @@ static bool gfx_ctx_x_bind_api(void *data, enum gfx_ctx_api api,
} }
g_api = GFX_CTX_OPENGL_ES_API; g_api = GFX_CTX_OPENGL_ES_API;
return ret; return ret;
}
#else #else
g_api = GFX_CTX_OPENGL_API; break;
return api == GFX_CTX_OPENGL_API;
#endif #endif
case GFX_CTX_VULKAN_API:
#ifdef HAVE_VULKAN
g_api = api;
return true;
#else
break;
#endif
case GFX_CTX_NONE:
default:
break;
}
return false;
} }
static void gfx_ctx_x_show_mouse(void *data, bool state) static void gfx_ctx_x_show_mouse(void *data, bool state)

View File

@ -28,7 +28,8 @@
using namespace std; using namespace std;
static uint32_t find_memory_type(const VkPhysicalDeviceMemoryProperties &mem_props, static uint32_t find_memory_type(
const VkPhysicalDeviceMemoryProperties &mem_props,
uint32_t device_reqs, uint32_t host_reqs) uint32_t device_reqs, uint32_t host_reqs)
{ {
uint32_t i; uint32_t i;
@ -43,7 +44,8 @@ static uint32_t find_memory_type(const VkPhysicalDeviceMemoryProperties &mem_pro
abort(); abort();
} }
static uint32_t find_memory_type_fallback(const VkPhysicalDeviceMemoryProperties &mem_props, static uint32_t find_memory_type_fallback(
const VkPhysicalDeviceMemoryProperties &mem_props,
uint32_t device_reqs, uint32_t host_reqs) uint32_t device_reqs, uint32_t host_reqs)
{ {
uint32_t i; uint32_t i;
@ -113,7 +115,8 @@ class DeferredDisposer
class Buffer class Buffer
{ {
public: public:
Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, Buffer(VkDevice device,
const VkPhysicalDeviceMemoryProperties &mem_props,
size_t size, VkBufferUsageFlags usage); size_t size, VkBufferUsageFlags usage);
~Buffer(); ~Buffer();
@ -133,7 +136,8 @@ class Buffer
class Framebuffer class Framebuffer
{ {
public: public:
Framebuffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, Framebuffer(VkDevice device,
const VkPhysicalDeviceMemoryProperties &mem_props,
const Size2D &max_size, VkFormat format); const Size2D &max_size, VkFormat format);
~Framebuffer(); ~Framebuffer();
@ -174,7 +178,8 @@ class Framebuffer
class Pass class Pass
{ {
public: public:
Pass(VkDevice device, const VkPhysicalDeviceMemoryProperties &memory_properties, Pass(VkDevice device,
const VkPhysicalDeviceMemoryProperties &memory_properties,
VkPipelineCache cache, unsigned num_sync_indices, bool final_pass) : VkPipelineCache cache, unsigned num_sync_indices, bool final_pass) :
device(device), device(device),
memory_properties(memory_properties), memory_properties(memory_properties),
@ -239,7 +244,8 @@ class Pass
unsigned sync_index; unsigned sync_index;
bool final_pass; bool final_pass;
Size2D get_output_size(const Size2D &original_size, const Size2D &max_source) const; Size2D get_output_size(const Size2D &original_size,
const Size2D &max_source) const;
VkPipeline pipeline = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE;
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
@ -302,17 +308,20 @@ struct vulkan_filter_chain
return shader_preset.get(); return shader_preset.get();
} }
void set_pass_info(unsigned pass, const vulkan_filter_chain_pass_info &info); void set_pass_info(unsigned pass,
const vulkan_filter_chain_pass_info &info);
void set_shader(unsigned pass, VkShaderStageFlags stage, void set_shader(unsigned pass, VkShaderStageFlags stage,
const uint32_t *spirv, size_t spirv_words); const uint32_t *spirv, size_t spirv_words);
bool init(); bool init();
bool update_swapchain_info(const vulkan_filter_chain_swapchain_info &info); bool update_swapchain_info(
const vulkan_filter_chain_swapchain_info &info);
void notify_sync_index(unsigned index); void notify_sync_index(unsigned index);
void set_input_texture(const vulkan_filter_chain_texture &texture); void set_input_texture(const vulkan_filter_chain_texture &texture);
void build_offscreen_passes(VkCommandBuffer cmd, const VkViewport &vp); void build_offscreen_passes(VkCommandBuffer cmd, const VkViewport &vp);
void build_viewport_pass(VkCommandBuffer cmd, const VkViewport &vp, const float *mvp); void build_viewport_pass(VkCommandBuffer cmd,
const VkViewport &vp, const float *mvp);
private: private:
VkDevice device; VkDevice device;
@ -338,7 +347,8 @@ struct vulkan_filter_chain
void set_swapchain_info(const vulkan_filter_chain_swapchain_info &info); void set_swapchain_info(const vulkan_filter_chain_swapchain_info &info);
}; };
vulkan_filter_chain::vulkan_filter_chain(const vulkan_filter_chain_create_info &info) vulkan_filter_chain::vulkan_filter_chain(
const vulkan_filter_chain_create_info &info)
: device(info.device), : device(info.device),
memory_properties(*info.memory_properties), memory_properties(*info.memory_properties),
cache(info.pipeline_cache) cache(info.pipeline_cache)
@ -353,7 +363,8 @@ vulkan_filter_chain::~vulkan_filter_chain()
flush(); flush();
} }
void vulkan_filter_chain::set_swapchain_info(const vulkan_filter_chain_swapchain_info &info) void vulkan_filter_chain::set_swapchain_info(
const vulkan_filter_chain_swapchain_info &info)
{ {
swapchain_info = info; swapchain_info = info;
set_num_sync_indices(info.num_indices); set_num_sync_indices(info.num_indices);
@ -389,7 +400,8 @@ void vulkan_filter_chain::set_num_passes(unsigned num_passes)
} }
} }
bool vulkan_filter_chain::update_swapchain_info(const vulkan_filter_chain_swapchain_info &info) bool vulkan_filter_chain::update_swapchain_info(
const vulkan_filter_chain_swapchain_info &info)
{ {
flush(); flush();
set_swapchain_info(info); set_swapchain_info(info);
@ -402,13 +414,17 @@ void vulkan_filter_chain::set_pass_info(unsigned pass,
pass_info[pass] = info; pass_info[pass] = info;
} }
void vulkan_filter_chain::set_shader(unsigned pass, VkShaderStageFlags stage, void vulkan_filter_chain::set_shader(
const uint32_t *spirv, size_t spirv_words) unsigned pass,
VkShaderStageFlags stage,
const uint32_t *spirv,
size_t spirv_words)
{ {
passes[pass]->set_shader(stage, spirv, spirv_words); passes[pass]->set_shader(stage, spirv, spirv_words);
} }
void vulkan_filter_chain::set_input_texture(const vulkan_filter_chain_texture &texture) void vulkan_filter_chain::set_input_texture(
const vulkan_filter_chain_texture &texture)
{ {
input_texture = texture; input_texture = texture;
} }
@ -436,7 +452,8 @@ bool vulkan_filter_chain::init()
for (unsigned i = 0; i < passes.size(); i++) for (unsigned i = 0; i < passes.size(); i++)
{ {
auto &pass = passes[i]; auto &pass = passes[i];
source = pass->set_pass_info(max_input_size, source, swapchain_info, pass_info[i]); source = pass->set_pass_info(max_input_size,
source, swapchain_info, pass_info[i]);
if (!pass->build()) if (!pass->build())
return false; return false;
} }
@ -447,11 +464,14 @@ bool vulkan_filter_chain::init()
void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd, void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd,
const VkViewport &vp) const VkViewport &vp)
{ {
unsigned i;
DeferredDisposer disposer(deferred_calls[current_sync_index]); DeferredDisposer disposer(deferred_calls[current_sync_index]);
const Texture original = { input_texture, passes.front()->get_source_filter() }; const Texture original = {
Texture source = { input_texture, passes.front()->get_source_filter() }; 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++) for (i = 0; i < passes.size() - 1; i++)
{ {
passes[i]->build_commands(disposer, cmd, passes[i]->build_commands(disposer, cmd,
original, source, vp, nullptr); original, source, vp, nullptr);
@ -465,12 +485,13 @@ void vulkan_filter_chain::build_offscreen_passes(VkCommandBuffer cmd,
} }
} }
void vulkan_filter_chain::build_viewport_pass(VkCommandBuffer cmd, const VkViewport &vp, const float *mvp) 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; Texture source;
DeferredDisposer disposer(deferred_calls[current_sync_index]);
const Texture original = {
input_texture, passes.front()->get_source_filter() };
if (passes.size() == 1) if (passes.size() == 1)
source = { input_texture, passes.back()->get_source_filter() }; source = { input_texture, passes.back()->get_source_filter() };
@ -488,7 +509,8 @@ void vulkan_filter_chain::build_viewport_pass(VkCommandBuffer cmd, const VkViewp
original, source, vp, mvp); original, source, vp, mvp);
} }
Buffer::Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props, Buffer::Buffer(VkDevice device,
const VkPhysicalDeviceMemoryProperties &mem_props,
size_t size, VkBufferUsageFlags usage) : size_t size, VkBufferUsageFlags usage) :
device(device), size(size) device(device), size(size)
{ {
@ -504,8 +526,10 @@ Buffer::Buffer(VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_prop
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
alloc.allocationSize = mem_reqs.size; alloc.allocationSize = mem_reqs.size;
alloc.memoryTypeIndex = find_memory_type(mem_props, mem_reqs.memoryTypeBits, alloc.memoryTypeIndex = find_memory_type(
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); mem_props, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
vkAllocateMemory(device, &alloc, NULL, &memory); vkAllocateMemory(device, &alloc, NULL, &memory);
vkBindBufferMemory(device, buffer, memory, 0); vkBindBufferMemory(device, buffer, memory, 0);
@ -545,16 +569,19 @@ void Pass::set_shader(VkShaderStageFlags stage,
if (stage == VK_SHADER_STAGE_VERTEX_BIT) if (stage == VK_SHADER_STAGE_VERTEX_BIT)
{ {
vertex_shader.clear(); vertex_shader.clear();
vertex_shader.insert(end(vertex_shader), spirv, spirv + spirv_words); vertex_shader.insert(end(vertex_shader),
spirv, spirv + spirv_words);
} }
else if (stage == VK_SHADER_STAGE_FRAGMENT_BIT) else if (stage == VK_SHADER_STAGE_FRAGMENT_BIT)
{ {
fragment_shader.clear(); fragment_shader.clear();
fragment_shader.insert(end(fragment_shader), spirv, spirv + spirv_words); fragment_shader.insert(end(fragment_shader),
spirv, spirv + spirv_words);
} }
} }
Size2D Pass::get_output_size(const Size2D &original, const Size2D &source) const Size2D Pass::get_output_size(const Size2D &original,
const Size2D &source) const
{ {
float width, height; float width, height;
switch (pass_info.scale_type_x) switch (pass_info.scale_type_x)
@ -670,28 +697,34 @@ bool Pass::init_pipeline_layout()
desc_counts.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }); desc_counts.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 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 }; VkDescriptorSetLayoutCreateInfo set_layout_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
set_layout_info.bindingCount = bindings.size(); set_layout_info.bindingCount = bindings.size();
set_layout_info.pBindings = bindings.data(); set_layout_info.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(device, &set_layout_info, NULL, &set_layout) != VK_SUCCESS) if (vkCreateDescriptorSetLayout(device,
&set_layout_info, NULL, &set_layout) != VK_SUCCESS)
return false; return false;
VkPipelineLayoutCreateInfo layout_info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; VkPipelineLayoutCreateInfo layout_info = {
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
layout_info.setLayoutCount = 1; layout_info.setLayoutCount = 1;
layout_info.pSetLayouts = &set_layout; layout_info.pSetLayouts = &set_layout;
if (vkCreatePipelineLayout(device, &layout_info, NULL, &pipeline_layout) != VK_SUCCESS) if (vkCreatePipelineLayout(device,
&layout_info, NULL, &pipeline_layout) != VK_SUCCESS)
return false; return false;
VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; VkDescriptorPoolCreateInfo pool_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
pool_info.maxSets = num_sync_indices; pool_info.maxSets = num_sync_indices;
pool_info.poolSizeCount = desc_counts.size(); pool_info.poolSizeCount = desc_counts.size();
pool_info.pPoolSizes = desc_counts.data(); pool_info.pPoolSizes = desc_counts.data();
if (vkCreateDescriptorPool(device, &pool_info, nullptr, &pool) != VK_SUCCESS) if (vkCreateDescriptorPool(device, &pool_info, nullptr, &pool) != VK_SUCCESS)
return false; return false;
VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; VkDescriptorSetAllocateInfo alloc_info = {
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
alloc_info.descriptorPool = pool; alloc_info.descriptorPool = pool;
alloc_info.descriptorSetCount = 1; alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &set_layout; alloc_info.pSetLayouts = &set_layout;
@ -709,7 +742,8 @@ bool Pass::init_pipeline()
return false; return false;
// Input assembly // Input assembly
VkPipelineInputAssemblyStateCreateInfo input_assembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; VkPipelineInputAssemblyStateCreateInfo input_assembly = {
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
// VAO state // VAO state
@ -729,14 +763,16 @@ bool Pass::init_pipeline()
binding.stride = 4 * sizeof(float); binding.stride = 4 * sizeof(float);
binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
VkPipelineVertexInputStateCreateInfo vertex_input = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; VkPipelineVertexInputStateCreateInfo vertex_input = {
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
vertex_input.vertexBindingDescriptionCount = 1; vertex_input.vertexBindingDescriptionCount = 1;
vertex_input.pVertexBindingDescriptions = &binding; vertex_input.pVertexBindingDescriptions = &binding;
vertex_input.vertexAttributeDescriptionCount = 2; vertex_input.vertexAttributeDescriptionCount = 2;
vertex_input.pVertexAttributeDescriptions = attributes; vertex_input.pVertexAttributeDescriptions = attributes;
// Raster state // Raster state
VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; VkPipelineRasterizationStateCreateInfo raster = {
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
raster.polygonMode = VK_POLYGON_MODE_FILL; raster.polygonMode = VK_POLYGON_MODE_FILL;
raster.cullMode = VK_CULL_MODE_NONE; raster.cullMode = VK_CULL_MODE_NONE;
raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
@ -747,19 +783,22 @@ bool Pass::init_pipeline()
// Blend state // Blend state
VkPipelineColorBlendAttachmentState blend_attachment = {0}; VkPipelineColorBlendAttachmentState blend_attachment = {0};
VkPipelineColorBlendStateCreateInfo blend = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; VkPipelineColorBlendStateCreateInfo blend = {
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
blend_attachment.blendEnable = false; blend_attachment.blendEnable = false;
blend_attachment.colorWriteMask = 0xf; blend_attachment.colorWriteMask = 0xf;
blend.attachmentCount = 1; blend.attachmentCount = 1;
blend.pAttachments = &blend_attachment; blend.pAttachments = &blend_attachment;
// Viewport state // Viewport state
VkPipelineViewportStateCreateInfo viewport = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; VkPipelineViewportStateCreateInfo viewport = {
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
viewport.viewportCount = 1; viewport.viewportCount = 1;
viewport.scissorCount = 1; viewport.scissorCount = 1;
// Depth-stencil state // Depth-stencil state
VkPipelineDepthStencilStateCreateInfo depth_stencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; VkPipelineDepthStencilStateCreateInfo depth_stencil = {
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
depth_stencil.depthTestEnable = false; depth_stencil.depthTestEnable = false;
depth_stencil.depthWriteEnable = false; depth_stencil.depthWriteEnable = false;
depth_stencil.depthBoundsTestEnable = false; depth_stencil.depthBoundsTestEnable = false;
@ -768,12 +807,15 @@ bool Pass::init_pipeline()
depth_stencil.maxDepthBounds = 1.0f; depth_stencil.maxDepthBounds = 1.0f;
// Multisample state // Multisample state
VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; VkPipelineMultisampleStateCreateInfo multisample = {
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
// Dynamic state // Dynamic state
VkPipelineDynamicStateCreateInfo dynamic = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; VkPipelineDynamicStateCreateInfo dynamic = {
static const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
static const VkDynamicState dynamics[] = {
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
dynamic.pDynamicStates = dynamics; dynamic.pDynamicStates = dynamics;
dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]); dynamic.dynamicStateCount = sizeof(dynamics) / sizeof(dynamics[0]);
@ -783,7 +825,8 @@ bool Pass::init_pipeline()
{ 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 }; VkShaderModuleCreateInfo module_info = {
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
module_info.codeSize = vertex_shader.size() * sizeof(uint32_t); module_info.codeSize = vertex_shader.size() * sizeof(uint32_t);
module_info.pCode = vertex_shader.data(); module_info.pCode = vertex_shader.data();
shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
@ -796,7 +839,8 @@ bool Pass::init_pipeline()
shader_stages[1].pName = "main"; shader_stages[1].pName = "main";
vkCreateShaderModule(device, &module_info, NULL, &shader_stages[1].module); vkCreateShaderModule(device, &module_info, NULL, &shader_stages[1].module);
VkGraphicsPipelineCreateInfo pipe = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; VkGraphicsPipelineCreateInfo pipe = {
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
pipe.stageCount = 2; pipe.stageCount = 2;
pipe.pStages = shader_stages; pipe.pStages = shader_stages;
pipe.pVertexInputState = &vertex_input; pipe.pVertexInputState = &vertex_input;
@ -807,10 +851,12 @@ bool Pass::init_pipeline()
pipe.pViewportState = &viewport; pipe.pViewportState = &viewport;
pipe.pDepthStencilState = &depth_stencil; pipe.pDepthStencilState = &depth_stencil;
pipe.pDynamicState = &dynamic; pipe.pDynamicState = &dynamic;
pipe.renderPass = final_pass ? swapchain_render_pass : framebuffer->get_render_pass(); pipe.renderPass = final_pass ? swapchain_render_pass :
framebuffer->get_render_pass();
pipe.layout = pipeline_layout; pipe.layout = pipeline_layout;
if (vkCreateGraphicsPipelines(device, cache, 1, &pipe, NULL, &pipeline) != VK_SUCCESS) if (vkCreateGraphicsPipelines(device,
cache, 1, &pipe, NULL, &pipeline) != VK_SUCCESS)
{ {
vkDestroyShaderModule(device, shader_stages[0].module, NULL); vkDestroyShaderModule(device, shader_stages[0].module, NULL);
vkDestroyShaderModule(device, shader_stages[1].module, NULL); vkDestroyShaderModule(device, shader_stages[1].module, NULL);
@ -839,13 +885,15 @@ bool Pass::init_samplers()
info.unnormalizedCoordinates = false; info.unnormalizedCoordinates = false;
info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
if (vkCreateSampler(device, &info, NULL, &samplers[VULKAN_FILTER_CHAIN_NEAREST]) != VK_SUCCESS) if (vkCreateSampler(device,
&info, NULL, &samplers[VULKAN_FILTER_CHAIN_NEAREST]) != VK_SUCCESS)
return false; return false;
info.magFilter = VK_FILTER_LINEAR; info.magFilter = VK_FILTER_LINEAR;
info.minFilter = VK_FILTER_LINEAR; info.minFilter = VK_FILTER_LINEAR;
if (vkCreateSampler(device, &info, NULL, &samplers[VULKAN_FILTER_CHAIN_LINEAR]) != VK_SUCCESS) if (vkCreateSampler(device,
&info, NULL, &samplers[VULKAN_FILTER_CHAIN_LINEAR]) != VK_SUCCESS)
return false; return false;
return true; return true;
@ -853,6 +901,7 @@ bool Pass::init_samplers()
bool Pass::init_buffers() bool Pass::init_buffers()
{ {
unsigned i;
// The final pass uses an MVP designed for [0, 1] range VBO. // 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. // For in-between passes, we just go with identity matrices, so keep it simple.
float pos_min = final_pass ? 0.0f : -1.0f; float pos_min = final_pass ? 0.0f : -1.0f;
@ -865,9 +914,11 @@ bool Pass::init_buffers()
}; };
ubos.clear(); ubos.clear();
for (unsigned i = 0; i < num_sync_indices; i++) for (i = 0; i < num_sync_indices; i++)
ubos.emplace_back(new Buffer(device, memory_properties, sizeof(UBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)); ubos.emplace_back(new Buffer(device,
vbo = unique_ptr<Buffer>(new Buffer(device, memory_properties, sizeof(vbo_data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); memory_properties, sizeof(UBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
vbo = unique_ptr<Buffer>(new Buffer(device,
memory_properties, sizeof(vbo_data), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
void *ptr = vbo->map(); void *ptr = vbo->map();
memcpy(ptr, vbo_data, sizeof(vbo_data)); memcpy(ptr, vbo_data, sizeof(vbo_data));
@ -880,7 +931,8 @@ bool Pass::build()
if (!final_pass) if (!final_pass)
{ {
framebuffer = unique_ptr<Framebuffer>( framebuffer = unique_ptr<Framebuffer>(
new Framebuffer(device, memory_properties, current_framebuffer_size, new Framebuffer(device, memory_properties,
current_framebuffer_size,
pass_info.rt_format)); pass_info.rt_format));
} }
@ -966,7 +1018,8 @@ void Pass::update_descriptor_set(
const Texture &original, const Texture &original,
const Texture &source) const Texture &source)
{ {
set_uniform_buffer(sets[sync_index], 0, ubos[sync_index]->get_buffer(), 0, sizeof(UBO)); 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], 1, original);
set_texture(sets[sync_index], 2, source); set_texture(sets[sync_index], 2, source);
} }
@ -984,7 +1037,8 @@ void Pass::build_commands(
{ original.texture.width, original.texture.height }, { original.texture.width, original.texture.height },
{ source.texture.width, source.texture.height }); { source.texture.width, source.texture.height });
if (size.width != current_framebuffer_size.width || size.height != current_framebuffer_size.height) if ( size.width != current_framebuffer_size.width
|| size.height != current_framebuffer_size.height)
{ {
if (framebuffer) if (framebuffer)
framebuffer->set_size(disposer, size); framebuffer->set_size(disposer, size);
@ -997,25 +1051,35 @@ void Pass::build_commands(
memcpy(u->MVP, mvp, sizeof(float) * 16); memcpy(u->MVP, mvp, sizeof(float) * 16);
else else
build_identity_matrix(u->MVP); build_identity_matrix(u->MVP);
build_vec4(u->output_size, current_framebuffer_size.width, current_framebuffer_size.height); build_vec4(u->output_size,
build_vec4(u->original_size, original.texture.width, original.texture.height); current_framebuffer_size.width,
build_vec4(u->source_size, source.texture.width, source.texture.height); 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(); ubos[sync_index]->unmap();
update_descriptor_set(original, source); update_descriptor_set(original, source);
// The final pass is always executed inside another render pass since // The final pass is always executed inside
// the frontend will want to overlay various things on top for the passes that end // another render pass since the frontend will
// up on-screen. // want to overlay various things on top for
// the passes that end up on-screen.
if (!final_pass) if (!final_pass)
{ {
// Render. // Render.
image_layout_transition(device, cmd, framebuffer->get_image(), image_layout_transition(device, cmd,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, framebuffer->get_image(),
VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); 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 }; VkRenderPassBeginInfo rp_info = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
VkClearValue clear_value; VkClearValue clear_value;
clear_value.color.float32[0] = 0.0f; clear_value.color.float32[0] = 0.0f;
clear_value.color.float32[1] = 0.0f; clear_value.color.float32[1] = 0.0f;
@ -1040,8 +1104,14 @@ void Pass::build_commands(
if (final_pass) if (final_pass)
{ {
const VkRect2D sci = { const VkRect2D sci = {
{ int32_t(current_viewport.x), int32_t(current_viewport.y) }, {
{ uint32_t(current_viewport.width), uint32_t(current_viewport.height) }, int32_t(current_viewport.x),
int32_t(current_viewport.y)
},
{
uint32_t(current_viewport.width),
uint32_t(current_viewport.height)
},
}; };
vkCmdSetViewport(cmd, 0, 1, &current_viewport); vkCmdSetViewport(cmd, 0, 1, &current_viewport);
vkCmdSetScissor(cmd, 0, 1, &sci); vkCmdSetScissor(cmd, 0, 1, &sci);
@ -1050,12 +1120,16 @@ void Pass::build_commands(
{ {
const VkViewport vp = { const VkViewport vp = {
0.0f, 0.0f, 0.0f, 0.0f,
float(current_framebuffer_size.width), float(current_framebuffer_size.height), float(current_framebuffer_size.width),
float(current_framebuffer_size.height),
0.0f, 1.0f 0.0f, 1.0f
}; };
const VkRect2D sci = { const VkRect2D sci = {
{ 0, 0 }, { 0, 0 },
{ current_framebuffer_size.width, current_framebuffer_size.height }, {
current_framebuffer_size.width,
current_framebuffer_size.height
},
}; };
vkCmdSetViewport(cmd, 0, 1, &vp); vkCmdSetViewport(cmd, 0, 1, &vp);
@ -1069,27 +1143,37 @@ void Pass::build_commands(
vkCmdEndRenderPass(cmd); vkCmdEndRenderPass(cmd);
// Barrier to sync with next pass. // Barrier to sync with next pass.
image_layout_transition(device, cmd, framebuffer->get_image(), image_layout_transition(
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, device,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, cmd,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); 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, Framebuffer::Framebuffer(
VkDevice device,
const VkPhysicalDeviceMemoryProperties &mem_props,
const Size2D &max_size, VkFormat format) : const Size2D &max_size, VkFormat format) :
device(device), device(device),
memory_properties(mem_props), memory_properties(mem_props),
size(max_size), size(max_size),
format(format) format(format)
{ {
RARCH_LOG("[Vulkan filter chain]: Creating framebuffer %u x %u.\n", max_size.width, max_size.height); RARCH_LOG("[Vulkan filter chain]: Creating framebuffer %u x %u.\n",
max_size.width, max_size.height);
init_render_pass(); init_render_pass();
init(nullptr); init(nullptr);
} }
void Framebuffer::init(DeferredDisposer *disposer) void Framebuffer::init(DeferredDisposer *disposer)
{ {
VkMemoryRequirements mem_reqs;
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
info.imageType = VK_IMAGE_TYPE_2D; info.imageType = VK_IMAGE_TYPE_2D;
info.format = format; info.format = format;
@ -1100,17 +1184,18 @@ void Framebuffer::init(DeferredDisposer *disposer)
info.arrayLayers = 1; info.arrayLayers = 1;
info.samples = VK_SAMPLE_COUNT_1_BIT; info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL; info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
vkCreateImage(device, &info, nullptr, &image); vkCreateImage(device, &info, nullptr, &image);
VkMemoryRequirements mem_reqs;
vkGetImageMemoryRequirements(device, image, &mem_reqs); vkGetImageMemoryRequirements(device, image, &mem_reqs);
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
alloc.allocationSize = mem_reqs.size; alloc.allocationSize = mem_reqs.size;
alloc.memoryTypeIndex = find_memory_type_fallback(memory_properties, mem_reqs.memoryTypeBits, alloc.memoryTypeIndex = find_memory_type_fallback(
memory_properties, mem_reqs.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
// Can reuse already allocated memory. // Can reuse already allocated memory.
@ -1132,7 +1217,8 @@ void Framebuffer::init(DeferredDisposer *disposer)
vkBindImageMemory(device, image, memory.memory, 0); vkBindImageMemory(device, image, memory.memory, 0);
VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; VkImageViewCreateInfo view_info = {
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format; view_info.format = format;
view_info.image = image; view_info.image = image;
@ -1152,8 +1238,10 @@ void Framebuffer::init(DeferredDisposer *disposer)
void Framebuffer::init_render_pass() void Framebuffer::init_render_pass()
{ {
VkRenderPassCreateInfo rp_info = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; VkRenderPassCreateInfo rp_info = {
VkAttachmentReference color_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; 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, // We will always write to the entire framebuffer,
// so we don't really need to clear. // so we don't really need to clear.
@ -1183,7 +1271,8 @@ void Framebuffer::init_render_pass()
void Framebuffer::init_framebuffer() void Framebuffer::init_framebuffer()
{ {
VkFramebufferCreateInfo info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; VkFramebufferCreateInfo info = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
info.renderPass = render_pass; info.renderPass = render_pass;
info.attachmentCount = 1; info.attachmentCount = 1;
info.pAttachments = &view; info.pAttachments = &view;
@ -1198,7 +1287,8 @@ void Framebuffer::set_size(DeferredDisposer &disposer, const Size2D &size)
{ {
this->size = size; this->size = size;
RARCH_LOG("[Vulkan filter chain]: Updating framebuffer size %u x %u.\n", size.width, size.height); 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 // The current framebuffers, etc, might still be in use
@ -1247,8 +1337,11 @@ vulkan_filter_chain_t *vulkan_filter_chain_new(
return new vulkan_filter_chain(*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) vulkan_filter_chain_t *vulkan_filter_chain_create_default(
const struct vulkan_filter_chain_create_info *info,
vulkan_filter_chain_filter filter)
{ {
struct vulkan_filter_chain_pass_info pass_info;
auto tmpinfo = *info; auto tmpinfo = *info;
tmpinfo.num_passes = 1; tmpinfo.num_passes = 1;
@ -1256,7 +1349,6 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_default(const struct vulkan_fi
if (!chain) if (!chain)
return nullptr; return nullptr;
struct vulkan_filter_chain_pass_info pass_info;
memset(&pass_info, 0, sizeof(pass_info)); memset(&pass_info, 0, sizeof(pass_info));
pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; pass_info.scale_type_x = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT;
pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT; pass_info.scale_type_y = VULKAN_FILTER_CHAIN_SCALE_VIEWPORT;
@ -1266,8 +1358,12 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_default(const struct vulkan_fi
pass_info.source_filter = filter; pass_info.source_filter = filter;
chain->set_pass_info(0, pass_info); 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_VERTEX_BIT,
chain->set_shader(0, VK_SHADER_STAGE_FRAGMENT_BIT, (const uint32_t*)opaque_frag_spv, opaque_frag_spv_len / sizeof(uint32_t)); (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()) if (!chain->init())
return nullptr; return nullptr;
@ -1284,7 +1380,8 @@ struct ConfigDeleter
} }
}; };
vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulkan_filter_chain_create_info *info, 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) const char *path, vulkan_filter_chain_filter filter)
{ {
unique_ptr<video_shader> shader{ new video_shader() }; unique_ptr<video_shader> shader{ new video_shader() };
@ -1318,7 +1415,8 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulka
glslang_output output; glslang_output output;
if (!glslang_compile_shader(pass->source.path, &output)) if (!glslang_compile_shader(pass->source.path, &output))
{ {
RARCH_ERR("Failed to compile shader: \"%s\".\n", pass->source.path); RARCH_ERR("Failed to compile shader: \"%s\".\n",
pass->source.path);
return nullptr; return nullptr;
} }
@ -1343,11 +1441,17 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulka
if (!pass->fbo.valid) 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_x = i + 1 == shader->passes
pass_info.scale_type_y = i + 1 == shader->passes ? VULKAN_FILTER_CHAIN_SCALE_VIEWPORT : VULKAN_FILTER_CHAIN_SCALE_SOURCE; ? 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_x = 1.0f;
pass_info.scale_y = 1.0f; pass_info.scale_y = 1.0f;
pass_info.rt_format = i + 1 == shader->passes ? tmpinfo.swapchain.format : VK_FORMAT_R8G8B8A8_UNORM; pass_info.rt_format = i + 1 == shader->passes
? tmpinfo.swapchain.format
: VK_FORMAT_R8G8B8A8_UNORM;
} }
else else
{ {
@ -1429,17 +1533,20 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulka
return chain.release(); return chain.release();
} }
struct video_shader *vulkan_filter_chain_get_preset(vulkan_filter_chain_t *chain) struct video_shader *vulkan_filter_chain_get_preset(
vulkan_filter_chain_t *chain)
{ {
return chain->get_shader_preset(); return chain->get_shader_preset();
} }
void vulkan_filter_chain_free(vulkan_filter_chain_t *chain) void vulkan_filter_chain_free(
vulkan_filter_chain_t *chain)
{ {
delete chain; delete chain;
} }
void vulkan_filter_chain_set_shader(vulkan_filter_chain_t *chain, void vulkan_filter_chain_set_shader(
vulkan_filter_chain_t *chain,
unsigned pass, unsigned pass,
VkShaderStageFlags stage, VkShaderStageFlags stage,
const uint32_t *spirv, const uint32_t *spirv,
@ -1448,20 +1555,23 @@ void vulkan_filter_chain_set_shader(vulkan_filter_chain_t *chain,
chain->set_shader(pass, stage, spirv, spirv_words); chain->set_shader(pass, stage, spirv, spirv_words);
} }
void vulkan_filter_chain_set_pass_info(vulkan_filter_chain_t *chain, void vulkan_filter_chain_set_pass_info(
vulkan_filter_chain_t *chain,
unsigned pass, unsigned pass,
const struct vulkan_filter_chain_pass_info *info) const struct vulkan_filter_chain_pass_info *info)
{ {
chain->set_pass_info(pass, *info); chain->set_pass_info(pass, *info);
} }
bool vulkan_filter_chain_update_swapchain_info(vulkan_filter_chain_t *chain, bool vulkan_filter_chain_update_swapchain_info(
vulkan_filter_chain_t *chain,
const vulkan_filter_chain_swapchain_info *info) const vulkan_filter_chain_swapchain_info *info)
{ {
return chain->update_swapchain_info(*info); return chain->update_swapchain_info(*info);
} }
void vulkan_filter_chain_notify_sync_index(vulkan_filter_chain_t *chain, void vulkan_filter_chain_notify_sync_index(
vulkan_filter_chain_t *chain,
unsigned index) unsigned index)
{ {
chain->notify_sync_index(index); chain->notify_sync_index(index);
@ -1472,19 +1582,22 @@ bool vulkan_filter_chain_init(vulkan_filter_chain_t *chain)
return chain->init(); return chain->init();
} }
void vulkan_filter_chain_set_input_texture(vulkan_filter_chain_t *chain, void vulkan_filter_chain_set_input_texture(
vulkan_filter_chain_t *chain,
const struct vulkan_filter_chain_texture *texture) const struct vulkan_filter_chain_texture *texture)
{ {
chain->set_input_texture(*texture); chain->set_input_texture(*texture);
} }
void vulkan_filter_chain_build_offscreen_passes(vulkan_filter_chain_t *chain, void vulkan_filter_chain_build_offscreen_passes(
vulkan_filter_chain_t *chain,
VkCommandBuffer cmd, const VkViewport *vp) VkCommandBuffer cmd, const VkViewport *vp)
{ {
chain->build_offscreen_passes(cmd, *vp); chain->build_offscreen_passes(cmd, *vp);
} }
void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain, void vulkan_filter_chain_build_viewport_pass(
vulkan_filter_chain_t *chain,
VkCommandBuffer cmd, const VkViewport *vp, const float *mvp) VkCommandBuffer cmd, const VkViewport *vp, const float *mvp)
{ {
chain->build_viewport_pass(cmd, *vp, mvp); chain->build_viewport_pass(cmd, *vp, mvp);

View File

@ -52,7 +52,8 @@ enum vulkan_filter_chain_scale
struct vulkan_filter_chain_pass_info struct vulkan_filter_chain_pass_info
{ {
/* For the last pass, make sure VIEWPORT scale with scale factors of 1 are used. */ /* 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_x;
enum vulkan_filter_chain_scale scale_type_y; enum vulkan_filter_chain_scale scale_type_y;
float scale_x; float scale_x;
@ -117,13 +118,16 @@ void vulkan_filter_chain_build_offscreen_passes(vulkan_filter_chain_t *chain,
void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain, void vulkan_filter_chain_build_viewport_pass(vulkan_filter_chain_t *chain,
VkCommandBuffer cmd, const VkViewport *vp, const float *mvp); 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, vulkan_filter_chain_t *vulkan_filter_chain_create_default(
const struct vulkan_filter_chain_create_info *info,
enum vulkan_filter_chain_filter filter); enum vulkan_filter_chain_filter filter);
vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset(const struct vulkan_filter_chain_create_info *info, 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); const char *path, enum vulkan_filter_chain_filter filter);
struct video_shader *vulkan_filter_chain_get_preset(vulkan_filter_chain_t *chain); struct video_shader *vulkan_filter_chain_get_preset(
vulkan_filter_chain_t *chain);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -276,9 +276,11 @@ static bool find_video_driver(void)
if (video_driver_ctl(RARCH_DISPLAY_CTL_IS_HW_CONTEXT, NULL)) if (video_driver_ctl(RARCH_DISPLAY_CTL_IS_HW_CONTEXT, NULL))
{ {
current_video = NULL;
struct retro_hw_render_callback *hwr = struct retro_hw_render_callback *hwr =
video_driver_callback(); video_driver_callback();
current_video = NULL;
(void)hwr;
#if defined(HAVE_VULKAN) #if defined(HAVE_VULKAN)
if (hwr && hw_render_context_is_vulkan(hwr->context_type)) if (hwr && hw_render_context_is_vulkan(hwr->context_type))

View File

@ -336,11 +336,11 @@ int generic_menu_iterate(void *data, void *userdata, enum menu_action action)
BIT64_SET(menu->state, MENU_STATE_POP_STACK); BIT64_SET(menu->state, MENU_STATE_POP_STACK);
break; break;
case ITERATE_TYPE_DEFAULT: case ITERATE_TYPE_DEFAULT:
/* FIXME: Crappy hack, needed for mouse controls to not be completely broken /* FIXME: Crappy hack, needed for mouse controls
* in case we press back. * to not be completely broken in case we press back.
* *
* We need to fix this entire mess, mouse controls should not rely on a * We need to fix this entire mess, mouse controls
* hack like this in order to work. */ * should not rely on a hack like this in order to work. */
selection = max(min(selection, (menu_entries_get_size() - 1)), 0); selection = max(min(selection, (menu_entries_get_size() - 1)), 0);
menu_entry_get(&entry, 0, selection, NULL, false); menu_entry_get(&entry, 0, selection, NULL, false);

View File

@ -293,7 +293,8 @@ static void* xui_init(void **userdata)
d3d_make_d3dpp(d3d, &video_info, &d3dpp); d3d_make_d3dpp(d3d, &video_info, &d3dpp);
hr = app.InitShared(d3d->dev, &d3dpp, (PFN_XUITEXTURELOADER)XuiTextureLoader); hr = app.InitShared(d3d->dev, &d3dpp,
(PFN_XUITEXTURELOADER)XuiTextureLoader);
if (FAILED(hr)) if (FAILED(hr))
{ {
@ -404,7 +405,7 @@ static void xui_frame(void *data)
XUIMessageRender msgRender; XUIMessageRender msgRender;
D3DXMATRIX matOrigView; D3DXMATRIX matOrigView;
LPDIRECT3DDEVICE d3dr; LPDIRECT3DDEVICE d3dr;
const char *message; const char *message = NULL;
D3DVIEWPORT vp_full = {0}; D3DVIEWPORT vp_full = {0};
d3d_video_t *d3d = (d3d_video_t*)video_driver_get_ptr(false); d3d_video_t *d3d = (d3d_video_t*)video_driver_get_ptr(false);
@ -424,7 +425,8 @@ static void xui_frame(void *data)
XuiRenderGetViewTransform( app.GetDC(), &matOrigView ); XuiRenderGetViewTransform( app.GetDC(), &matOrigView );
XuiMessageRender( &msg, &msgRender, app.GetDC(), 0xffffffff, XUI_BLEND_NORMAL ); XuiMessageRender( &msg, &msgRender,
app.GetDC(), 0xffffffff, XUI_BLEND_NORMAL );
XuiSendMessage( app.GetRootObj(), &msg ); XuiSendMessage( app.GetRootObj(), &msg );
XuiRenderSetViewTransform( app.GetDC(), &matOrigView ); XuiRenderSetViewTransform( app.GetDC(), &matOrigView );
@ -452,9 +454,7 @@ static void blit_line(int x, int y, const char *message, bool green)
static void xui_render_background(void) static void xui_render_background(void)
{ {
bool libretro_running = menu_display_ctl(MENU_DISPLAY_CTL_LIBRETRO_RUNNING, NULL); if (menu_display_ctl(MENU_DISPLAY_CTL_LIBRETRO_RUNNING, NULL))
if (libretro_running)
XuiElementSetShow(m_background, FALSE); XuiElementSetShow(m_background, FALSE);
else else
XuiElementSetShow(m_background, TRUE); XuiElementSetShow(m_background, TRUE);
@ -666,13 +666,15 @@ static void xui_list_free(file_list_t *list, size_t idx,
static void xui_list_clear(file_list_t *list) static void xui_list_clear(file_list_t *list)
{ {
XuiListDeleteItems(m_menulist, 0, XuiListGetItemCount(m_menulist)); XuiListDeleteItems(m_menulist,
0, XuiListGetItemCount(m_menulist));
} }
static void xui_list_set_selection(void *data, file_list_t *list) static void xui_list_set_selection(void *data, file_list_t *list)
{ {
if (list) if (list)
XuiListSetCurSel(m_menulist, file_list_get_directory_ptr(list)); XuiListSetCurSel(m_menulist,
file_list_get_directory_ptr(list));
} }
static int xui_environ(menu_environ_cb_t type, void *data) static int xui_environ(menu_environ_cb_t type, void *data)

View File

@ -213,8 +213,10 @@ static void zarch_zui_font(void)
menu_display_ctl(MENU_DISPLAY_CTL_FONT_SIZE, &font_size); menu_display_ctl(MENU_DISPLAY_CTL_FONT_SIZE, &font_size);
fill_pathname_join(mediapath, settings->assets_directory, "zarch", sizeof(mediapath)); fill_pathname_join(mediapath,
fill_pathname_join(fontpath, mediapath, "Roboto-Condensed.ttf", sizeof(fontpath)); settings->assets_directory, "zarch", sizeof(mediapath));
fill_pathname_join(fontpath,
mediapath, "Roboto-Condensed.ttf", sizeof(fontpath));
font_info.path = fontpath; font_info.path = fontpath;
font_info.size = font_size; font_info.size = font_size;
@ -250,7 +252,8 @@ static int16_t zarch_zui_input_state(zui_t *zui, enum zarch_zui_input_state stat
case MENU_POINTER_ZARCH_Y: case MENU_POINTER_ZARCH_Y:
return menu_input_pointer_state(MENU_POINTER_Y_AXIS); return menu_input_pointer_state(MENU_POINTER_Y_AXIS);
case MENU_ZARCH_PRESSED: case MENU_ZARCH_PRESSED:
if (menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON) || menu_input_pointer_state(MENU_POINTER_PRESSED)) if ( menu_input_mouse_state(MENU_MOUSE_LEFT_BUTTON)
|| menu_input_pointer_state(MENU_POINTER_PRESSED))
return 1; return 1;
if (zui->action == MENU_ACTION_OK) if (zui->action == MENU_ACTION_OK)
return 1; return 1;
@ -260,7 +263,8 @@ static int16_t zarch_zui_input_state(zui_t *zui, enum zarch_zui_input_state stat
return 0; return 0;
} }
static bool zarch_zui_check_button_down(zui_t *zui, unsigned id, int x1, int y1, int x2, int y2) static bool zarch_zui_check_button_down(zui_t *zui,
unsigned id, int x1, int y1, int x2, int y2)
{ {
bool result = false; bool result = false;
bool inside = menu_input_mouse_check_hitbox(x1, y1, x2, y2); bool inside = menu_input_mouse_check_hitbox(x1, y1, x2, y2);
@ -268,7 +272,8 @@ static bool zarch_zui_check_button_down(zui_t *zui, unsigned id, int x1, int y1,
if (inside) if (inside)
zui->item.hot = id; zui->item.hot = id;
if (zui->item.hot == id && zarch_zui_input_state(zui, MENU_ZARCH_PRESSED)) if ( zui->item.hot == id
&& zarch_zui_input_state(zui, MENU_ZARCH_PRESSED))
{ {
result = true; result = true;
zui->item.active = id; zui->item.active = id;
@ -277,7 +282,8 @@ static bool zarch_zui_check_button_down(zui_t *zui, unsigned id, int x1, int y1,
return result; return result;
} }
static bool zarch_zui_check_button_up(zui_t *zui, unsigned id, int x1, int y1, int x2, int y2) static bool zarch_zui_check_button_up(zui_t *zui,
unsigned id, int x1, int y1, int x2, int y2)
{ {
bool result = false; bool result = false;
bool inside = menu_input_mouse_check_hitbox(x1, y1, x2, y2); bool inside = menu_input_mouse_check_hitbox(x1, y1, x2, y2);
@ -285,7 +291,8 @@ static bool zarch_zui_check_button_up(zui_t *zui, unsigned id, int x1, int y1, i
if (inside) if (inside)
zui->item.hot = id; zui->item.hot = id;
if (zui->item.active == id && !zarch_zui_input_state(zui, MENU_ZARCH_PRESSED)) if ( zui->item.active == id
&& !zarch_zui_input_state(zui, MENU_ZARCH_PRESSED))
{ {
if (zui->item.hot == id) if (zui->item.hot == id)
result = true; result = true;
@ -314,7 +321,8 @@ static unsigned zarch_zui_hash(zui_t *zui, const char *s)
return zui->hash = hval; return zui->hash = hval;
} }
static void zarch_zui_draw_text(zui_t *zui, uint32_t color, int x, int y, const char *text) static void zarch_zui_draw_text(zui_t *zui,
uint32_t color, int x, int y, const char *text)
{ {
struct font_params params; struct font_params params;
@ -375,14 +383,16 @@ static float zarch_zui_randf(float min, float max)
return (rand() * ((max - min) / RAND_MAX)) + min; return (rand() * ((max - min) / RAND_MAX)) + min;
} }
static float zarch_zui_scalef(float val, float oldmin, float oldmax, float newmin, float newmax) static float zarch_zui_scalef(float val,
float oldmin, float oldmax, float newmin, float newmax)
{ {
return (((val - oldmin) * (newmax - newmin)) / (oldmax - oldmin)) + newmin; return (((val - oldmin) * (newmax - newmin)) / (oldmax - oldmin)) + newmin;
} }
#define NPARTICLES 100 #define NPARTICLES 100
static void zarch_zui_snow(zui_t *zui, gfx_coord_array_t *ca, int width, int height) static void zarch_zui_snow(zui_t *zui, gfx_coord_array_t *ca,
int width, int height)
{ {
static part_t particles[NPARTICLES]; static part_t particles[NPARTICLES];
static bool initialized = false; static bool initialized = false;
@ -404,11 +414,11 @@ static void zarch_zui_snow(zui_t *zui, gfx_coord_array_t *ca, int width, int hei
int16_t mouse_x = zarch_zui_input_state(zui, MENU_ZARCH_MOUSE_X); int16_t mouse_x = zarch_zui_input_state(zui, MENU_ZARCH_MOUSE_X);
p->y += p->yspeed; p->y += p->yspeed;
p->x += zarch_zui_scalef(mouse_x, 0, width, -0.3, 0.3) + p->xspeed; p->x += zarch_zui_scalef(mouse_x, 0, width, -0.3, 0.3);
p->x += p->xspeed;
p->alive = p->y >= 0 && p->y < height && p->x >= 0 && p->x < width;
p->alive = p->y >= 0 && p->y < height
&& p->x >= 0 && p->x < width;
} }
else if (max_gen > 0 && timeout <= 0) else if (max_gen > 0 && timeout <= 0)
{ {
@ -447,13 +457,15 @@ static void zarch_zui_snow(zui_t *zui, gfx_coord_array_t *ca, int width, int hei
colors[j] = alpha; colors[j] = alpha;
} }
zarch_zui_push_quad(width, height, colors, ca, p->x-2, p->y-2, p->x+2, p->y+2); zarch_zui_push_quad(width, height,
colors, ca, p->x-2, p->y-2, p->x+2, p->y+2);
j++; j++;
} }
} }
static bool zarch_zui_button_full(zui_t *zui, int x1, int y1, int x2, int y2, const char *label) static bool zarch_zui_button_full(zui_t *zui,
int x1, int y1, int x2, int y2, const char *label)
{ {
unsigned id = zarch_zui_hash(zui, label); unsigned id = zarch_zui_hash(zui, label);
bool active = zarch_zui_check_button_up(zui, id, x1, y1, x2, y2); bool active = zarch_zui_check_button_up(zui, id, x1, y1, x2, y2);
@ -470,7 +482,8 @@ static bool zarch_zui_button_full(zui_t *zui, int x1, int y1, int x2, int y2, co
static bool zarch_zui_button(zui_t *zui, int x1, int y1, const char *label) static bool zarch_zui_button(zui_t *zui, int x1, int y1, const char *label)
{ {
return zarch_zui_button_full(zui, x1, y1, x1 + zarch_zui_strwidth(zui->fb_buf, label, 1.0) + 24, y1 + 64, label); return zarch_zui_button_full(zui, x1, y1, x1
+ zarch_zui_strwidth(zui->fb_buf, label, 1.0) + 24, y1 + 64, label);
} }
static bool zarch_zui_list_item(zui_t *zui, zui_tabbed_t *tab, int x1, int y1, static bool zarch_zui_list_item(zui_t *zui, zui_tabbed_t *tab, int x1, int y1,
@ -506,7 +519,8 @@ static bool zarch_zui_list_item(zui_t *zui, zui_tabbed_t *tab, int x1, int y1,
} }
else else
{ {
if (zui->active_id != item_id && zui->pending_selection == item_id) if ( zui->active_id != item_id
&& zui->pending_selection == item_id)
set_active_id = true; set_active_id = true;
} }
@ -542,7 +556,8 @@ static void zarch_zui_tabbed_begin(zui_t *zui, zui_tabbed_t *tab, int x, int y)
tab->tabline_size = 60 + 4; tab->tabline_size = 60 + 4;
} }
static bool zarch_zui_tab(zui_t *zui, zui_tabbed_t *tab, const char *label, unsigned tab_id) static bool zarch_zui_tab(zui_t *zui, zui_tabbed_t *tab,
const char *label, unsigned tab_id)
{ {
bool active; bool active;
int x1, y1, x2, y2; int x1, y1, x2, y2;
@ -656,7 +671,8 @@ static void zarch_zui_render_lay_root_load_free(zui_t *zui)
zui->load_dlist = NULL; zui->load_dlist = NULL;
} }
static void zarch_zui_render_lay_root_load_set_new_path(zui_t *zui, const char *newpath) static void zarch_zui_render_lay_root_load_set_new_path(zui_t *zui,
const char *newpath)
{ {
if (!zui) if (!zui)
return; return;
@ -685,23 +701,29 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
core_info_t *core_info = NULL; core_info_t *core_info = NULL;
core_info_ctl(CORE_INFO_CTL_CURRENT_CORE_GET, &core_info); core_info_ctl(CORE_INFO_CTL_CURRENT_CORE_GET, &core_info);
zui->load_dlist = dir_list_new(zui->load_cwd, core_info->supported_extensions, true, true); zui->load_dlist = dir_list_new(zui->load_cwd,
core_info->supported_extensions, true, true);
dir_list_sort(zui->load_dlist, true); dir_list_sort(zui->load_dlist, true);
zui->load_dlist_first = 0; zui->load_dlist_first = 0;
} }
cwd_offset = min(strlen(zui->load_cwd), 60); cwd_offset = min(strlen(zui->load_cwd), 60);
zarch_zui_draw_text(zui, ZUI_FG_NORMAL, 15, tabbed->tabline_size + 5 + 41, &zui->load_cwd[strlen(zui->load_cwd) - cwd_offset]); zarch_zui_draw_text(zui, ZUI_FG_NORMAL, 15,
tabbed->tabline_size + 5 + 41,
&zui->load_cwd[strlen(zui->load_cwd) - cwd_offset]);
if (zarch_zui_button(zui, zui->width - 290 - 129, tabbed->tabline_size + 5, "Home")) if (zarch_zui_button(zui, zui->width - 290 - 129,
tabbed->tabline_size + 5, "Home"))
zarch_zui_render_lay_root_load_free(zui); zarch_zui_render_lay_root_load_free(zui);
if (zui->load_dlist) if (zui->load_dlist)
{ {
fill_pathname_parent_dir(parent_dir, zui->load_cwd, sizeof(parent_dir)); fill_pathname_parent_dir(parent_dir,
zui->load_cwd, sizeof(parent_dir));
if (!string_is_empty(parent_dir) && if (!string_is_empty(parent_dir) &&
zarch_zui_list_item(zui, tabbed, 0, tabbed->tabline_size + 73, " ..", 0, NULL /* TODO/FIXME */)) zarch_zui_list_item(zui, tabbed, 0,
tabbed->tabline_size + 73, " ..", 0, NULL /* TODO/FIXME */))
{ {
zarch_zui_render_lay_root_load_set_new_path(zui, parent_dir); zarch_zui_render_lay_root_load_set_new_path(zui, parent_dir);
} }
@ -713,7 +735,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
for (i = 0; i < size; ++i) for (i = 0; i < size; ++i)
{ {
const char *basename = path_basename(zui->load_dlist->elems[i].data); const char *basename =
path_basename(zui->load_dlist->elems[i].data);
if (basename[0] != '.') if (basename[0] != '.')
break; break;
skip++; skip++;
@ -726,7 +749,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
else if (zui->load_dlist_first > (int)size - 5) else if (zui->load_dlist_first > (int)size - 5)
zui->load_dlist_first = size - 5; zui->load_dlist_first = size - 5;
zui->load_dlist_first = min(max(zui->load_dlist_first, 0), size - 5 - skip); zui->load_dlist_first = min(max(zui->load_dlist_first, 0),
size - 5 - skip);
for (i = skip + zui->load_dlist_first; i < size; ++i) for (i = skip + zui->load_dlist_first; i < size; ++i)
{ {
@ -747,7 +771,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
if (path_is_directory(path)) if (path_is_directory(path))
strncat(label, "/", sizeof(label)-1); strncat(label, "/", sizeof(label)-1);
if (zarch_zui_list_item(zui, tabbed, 0, tabbed->tabline_size + 73 + j * 54, if (zarch_zui_list_item(zui, tabbed, 0,
tabbed->tabline_size + 73 + j * 54,
label, i, NULL)) label, i, NULL))
{ {
if (path_is_directory(path)) if (path_is_directory(path))
@ -758,7 +783,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
zui->pick_cores = NULL; zui->pick_cores = NULL;
zui->pick_supported = 0; zui->pick_supported = 0;
strncpy(zui->pick_content, path, sizeof(zui->pick_content)-1); strncpy(zui->pick_content,
path, sizeof(zui->pick_content)-1);
core_info_ctl(CORE_INFO_CTL_LIST_GET, &list); core_info_ctl(CORE_INFO_CTL_LIST_GET, &list);
@ -781,7 +807,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed)
return 0; return 0;
} }
static int zarch_zui_render_lay_root_collections(zui_t *zui, zui_tabbed_t *tabbed) static int zarch_zui_render_lay_root_collections(
zui_t *zui, zui_tabbed_t *tabbed)
{ {
if (zarch_zui_tab(zui, tabbed, "Collections", 2)) if (zarch_zui_tab(zui, tabbed, "Collections", 2))
{ {
@ -791,7 +818,8 @@ static int zarch_zui_render_lay_root_collections(zui_t *zui, zui_tabbed_t *tabbe
return 0; return 0;
} }
static int zarch_zui_render_lay_root_downloads(zui_t *zui, zui_tabbed_t *tabbed) static int zarch_zui_render_lay_root_downloads(
zui_t *zui, zui_tabbed_t *tabbed)
{ {
if (zarch_zui_tab(zui, tabbed, "Download", 3)) if (zarch_zui_tab(zui, tabbed, "Download", 3))
{ {
@ -855,7 +883,8 @@ static int zarch_zui_render_lay_root(zui_t *zui)
else else
zui->pending_selection = -1; zui->pending_selection = -1;
zarch_zui_push_quad(zui->width, zui->height, ZUI_BG_HILITE, &zui->ca, 0, 60, zui->width - 290 - 40, 60+4); zarch_zui_push_quad(zui->width, zui->height,
ZUI_BG_HILITE, &zui->ca, 0, 60, zui->width - 290 - 40, 60+4);
return 0; return 0;
} }
@ -923,7 +952,8 @@ static int zarch_zui_render_pick_core(zui_t *zui)
if (!zui->pick_supported) if (!zui->pick_supported)
{ {
zarch_zui_list_item(zui, &tabbed, 0, 54, "Content unsupported", 0, NULL /* TODO/FIXME */); zarch_zui_list_item(zui, &tabbed, 0, 54,
"Content unsupported", 0, NULL /* TODO/FIXME */);
zui->active_id = 0; zui->active_id = 0;
return 1; return 1;
} }
@ -999,7 +1029,8 @@ static void zarch_frame(void *data)
menu_display_ctl(MENU_DISPLAY_CTL_FONT_BIND_BLOCK, &zui->tmp_block); menu_display_ctl(MENU_DISPLAY_CTL_FONT_BIND_BLOCK, &zui->tmp_block);
zarch_zui_push_quad(zui->width, zui->height, ZUI_BG_SCREEN, &zui->ca, 0, 0, zui->width, zui->height); zarch_zui_push_quad(zui->width, zui->height, ZUI_BG_SCREEN,
&zui->ca, 0, 0, zui->width, zui->height);
zarch_zui_snow(zui, &zui->ca, zui->width, zui->height); zarch_zui_snow(zui, &zui->ca, zui->width, zui->height);
switch (layout) switch (layout)
@ -1078,7 +1109,8 @@ static void *zarch_init(void **userdata)
int unused; int unused;
zui_t *zui = NULL; zui_t *zui = NULL;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
menu_handle_t *menu = (menu_handle_t*)calloc(1, sizeof(*menu)); menu_handle_t *menu = (menu_handle_t*)
calloc(1, sizeof(*menu));
if (!menu) if (!menu)
goto error; goto error;
@ -1112,7 +1144,8 @@ static void *zarch_init(void **userdata)
if (!string_is_empty(settings->menu.wallpaper)) if (!string_is_empty(settings->menu.wallpaper))
rarch_task_push_image_load(settings->menu.wallpaper, rarch_task_push_image_load(settings->menu.wallpaper,
"cb_menu_wallpaper", menu_display_handle_wallpaper_upload, NULL); "cb_menu_wallpaper",
menu_display_handle_wallpaper_upload, NULL);
zui->ca.allocated = 0; zui->ca.allocated = 0;
@ -1276,18 +1309,22 @@ static bool zarch_menu_init_list(void *data)
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
strlcpy(info.label, menu_hash_to_str(MENU_VALUE_HISTORY_TAB), sizeof(info.label)); strlcpy(info.label,
menu_hash_to_str(MENU_VALUE_HISTORY_TAB), sizeof(info.label));
menu_entries_push(menu_stack, info.path, info.label, info.type, info.flags, 0); menu_entries_push(menu_stack,
info.path, info.label, info.type, info.flags, 0);
#if 0 #if 0
menu_entries_increment_menu_stack(); menu_entries_increment_menu_stack();
strlcpy(info.label, menu_hash_to_str(MENU_VALUE_MAIN_MENU), sizeof(info.label)); strlcpy(info.label,
menu_hash_to_str(MENU_VALUE_MAIN_MENU), sizeof(info.label));
menu_stack = menu_entries_get_menu_stack_ptr(1); menu_stack = menu_entries_get_menu_stack_ptr(1);
menu_entries_push(menu_stack, info.path, info.label, info.type, info.flags, 0); menu_entries_push(menu_stack,
info.path, info.label, info.type, info.flags, 0);
#endif #endif
event_cmd_ctl(EVENT_CMD_HISTORY_INIT, NULL); event_cmd_ctl(EVENT_CMD_HISTORY_INIT, NULL);

View File

@ -126,7 +126,8 @@ static void menu_display_d3d_draw(void *data)
draw->height = 1; draw->height = 1;
if (!mat) if (!mat)
mat = (math_matrix_4x4*)menu_display_d3d_get_default_mvp(); mat = (math_matrix_4x4*)
menu_display_d3d_get_default_mvp();
if (!draw->coords->vertex) if (!draw->coords->vertex)
draw->coords->vertex = &d3d_vertexes[0]; draw->coords->vertex = &d3d_vertexes[0];
if (!draw->coords->tex_coord) if (!draw->coords->tex_coord)

View File

@ -53,21 +53,23 @@ static void *menu_display_vk_get_default_mvp(void)
return &vk->mvp_no_rot; return &vk->mvp_no_rot;
} }
static unsigned to_display_pipeline(enum menu_display_prim_type prim_type, bool blend) static unsigned to_display_pipeline(
enum menu_display_prim_type prim_type, bool blend)
{ {
return ((prim_type == MENU_DISPLAY_PRIM_TRIANGLESTRIP) << 1) | (blend << 0); return ((prim_type == MENU_DISPLAY_PRIM_TRIANGLESTRIP) << 1) | (blend << 0);
} }
static void menu_display_vk_draw(void *data) static void menu_display_vk_draw(void *data)
{ {
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; unsigned i;
struct vk_buffer_range range;
struct vk_texture *texture = NULL;
const float *vertex = NULL;
const float *tex_coord = NULL;
const float *color = NULL;
math_matrix_4x4 *mat = NULL;
struct vk_vertex *pv = NULL;
menu_display_ctx_draw_t *draw = (menu_display_ctx_draw_t*)data;
vk_t *vk = vk_get_ptr(); vk_t *vk = vk_get_ptr();
if (!vk) if (!vk)
return; return;
@ -120,7 +122,8 @@ static void menu_display_vk_draw(void *data)
{ {
const struct vk_draw_triangles call = { const struct vk_draw_triangles call = {
vk->display.pipelines[to_display_pipeline(draw->prim_type, vk->display.blend)], vk->display.pipelines[
to_display_pipeline(draw->prim_type, vk->display.blend)],
texture, texture,
texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest, texture->default_smooth ? vk->samplers.linear : vk->samplers.nearest,
mat, mat,

View File

@ -1446,11 +1446,11 @@ int runloop_iterate(unsigned *sleep_ms)
unlock_autosave(); unlock_autosave();
#endif #endif
if (!settings->fastforward_ratio)
return 0;
#ifdef HAVE_MENU #ifdef HAVE_MENU
end: end:
#endif #endif
if (!settings->fastforward_ratio)
return 0;
current = retro_get_time_usec(); current = retro_get_time_usec();
target = frame_limit_last_time + target = frame_limit_last_time +