diff --git a/Makefile.common b/Makefile.common index a49f7125a4..d3c49f1b97 100644 --- a/Makefile.common +++ b/Makefile.common @@ -361,8 +361,19 @@ ifeq ($(HAVE_NEON),1) OBJ += audio/audio_utils_neon.o endif +HW_CONTEXT_MENU_DRIVERS=$(HAVE_RGUI) + +ifeq ($(HW_CONTEXT_MENU_DRIVERS),0) +ifeq ($(HAVE_GL_CONTEXT),1) + HW_CONTEXT_MENU_DRIVERS=1 +endif +ifeq ($(HAVE_VULKAN),1) + HW_CONTEXT_MENU_DRIVERS=1 +endif +endif + # XMB and MaterialUI are always enabled if supported and not explicitly disabled -ifeq ($(HAVE_RGUI)$(HAVE_GL_CONTEXT), 11) +ifeq ($(HW_CONTEXT_MENU_DRIVERS), 1) ifeq ($(HAVE_ZARCH),) HAVE_ZARCH = 1 endif @@ -586,6 +597,13 @@ OBJ += gfx/video_context_driver.o \ libretro-common/gfx/math/matrix_4x4.o \ libretro-common/gfx/math/matrix_3x3.o +ifeq ($(HAVE_KMS), 1) + HAVE_AND_WILL_USE_DRM = 1 + OBJ += gfx/drivers_context/drm_ctx.o + DEFINES += $(GBM_CFLAGS) $(DRM_CFLAGS) $(EGL_CFLAGS) + LIBS += $(GBM_LIBS) $(DRM_LIBS) $(EGL_LIBS) +endif + ifeq ($(HAVE_GL_CONTEXT), 1) DEFINES += -DHAVE_OPENGL -DHAVE_GLSL OBJ += gfx/drivers/gl.o \ @@ -597,13 +615,6 @@ ifeq ($(HAVE_GL_CONTEXT), 1) OBJ += menu/drivers_display/menu_display_gl.o endif - ifeq ($(HAVE_KMS), 1) - HAVE_AND_WILL_USE_DRM = 1 - OBJ += gfx/drivers_context/drm_egl_ctx.o - DEFINES += $(GBM_CFLAGS) $(DRM_CFLAGS) $(EGL_CFLAGS) - LIBS += $(GBM_LIBS) $(DRM_LIBS) $(EGL_LIBS) - endif - ifeq ($(HAVE_VIDEOCORE), 1) OBJ += gfx/drivers_context/vc_egl_ctx.o DEFINES += $(EGL_CFLAGS) diff --git a/command_event.c b/command_event.c index bd00e37262..f11926ed74 100644 --- a/command_event.c +++ b/command_event.c @@ -638,18 +638,6 @@ static bool event_save_auto_state(void) return true; } -static void event_init_remapping(void) -{ - settings_t *settings = config_get_ptr(); - const char *path = settings->input.remapping_path; - config_file_t *conf = config_file_new(path); - - if (!settings->input.remap_binds_enable || !conf) - return; - - input_remapping_load_file(conf, path); -} - /** * event_save_core_config: * @@ -684,7 +672,6 @@ static bool event_save_core_config(void) RARCH_ERR("%s\n", msg_hash_to_str(MSG_CONFIG_DIRECTORY_NOT_SET)); return false; } - /* Infer file name based on libretro core. */ if (*settings->libretro && path_file_exists(settings->libretro)) { @@ -700,14 +687,12 @@ static bool event_save_core_config(void) path_remove_extension(config_name); fill_pathname_join(config_path, config_dir, config_name, sizeof(config_path)); - if (i) snprintf(tmp, sizeof(tmp), "-%u.cfg", i); else strlcpy(tmp, ".cfg", sizeof(tmp)); - fill_string_join(config_path, tmp, sizeof(config_path)); - + snprintf(config_path, sizeof(config_path), "%s%s", config_path, tmp); if (!path_file_exists(config_path)) { found_path = true; @@ -765,8 +750,10 @@ static bool event_save_core_config(void) **/ void event_save_current_config(void) { + char msg[128]; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); + bool ret = false; if (settings->config_save_on_exit && *global->path.config) { @@ -774,15 +761,29 @@ void event_save_current_config(void) * needed on consoles for core switching and reusing last good * config for new cores. */ - config_save_file(global->path.config); /* Flush out the core specific config. */ if (*global->path.core_specific_config && settings->core_specific_config) - config_save_file(global->path.core_specific_config); + ret = config_save_file(global->path.core_specific_config); + else + ret = config_save_file(global->path.config); } - event_cmd_ctl(EVENT_CMD_AUTOSAVE_STATE, NULL); + if (ret) + { + snprintf(msg, sizeof(msg), "Saved new config to \"%s\".", + global->path.config); + RARCH_LOG("%s\n", msg); + } + else + { + snprintf(msg, sizeof(msg), "Failed saving config to \"%s\".", + global->path.config); + RARCH_ERR("%s\n", msg); + } + + runloop_msg_queue_push(msg, 1, 180, true); } /** @@ -1133,12 +1134,6 @@ bool event_cmd_ctl(enum event_command cmd, void *data) case EVENT_CMD_CHEATS_APPLY: cheat_manager_apply_cheats(); break; - case EVENT_CMD_REMAPPING_DEINIT: - break; - case EVENT_CMD_REMAPPING_INIT: - event_cmd_ctl(EVENT_CMD_REMAPPING_DEINIT, NULL); - event_init_remapping(); - break; case EVENT_CMD_REWIND_DEINIT: #ifdef HAVE_NETPLAY if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) diff --git a/command_event.h b/command_event.h index 8db27d32d1..0548d330d1 100644 --- a/command_event.h +++ b/command_event.h @@ -201,8 +201,6 @@ enum event_command /* Toggles fullscreen mode. */ EVENT_CMD_FULLSCREEN_TOGGLE, EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG, - EVENT_CMD_REMAPPING_INIT, - EVENT_CMD_REMAPPING_DEINIT, EVENT_CMD_VOLUME_UP, EVENT_CMD_VOLUME_DOWN, EVENT_CMD_EXEC diff --git a/configuration.c b/configuration.c index 9aee5162ba..ae26ae8b65 100644 --- a/configuration.c +++ b/configuration.c @@ -1564,8 +1564,6 @@ static bool config_load_file(const char *path, bool set_defaults) } } - config_get_path(conf, "input_remapping_path", settings->input.remapping_path, - sizeof(settings->input.remapping_path)); config_get_path(conf, "resampler_directory", settings->resampler_directory, sizeof(settings->resampler_directory)); config_get_path(conf, "cache_directory", settings->cache_directory, @@ -2167,7 +2165,6 @@ bool config_load_remap(void) else { RARCH_LOG("Remaps: no game-specific remap found at %s\n", game_path); - *settings->input.remapping_path= '\0'; input_remapping_set_defaults(); } @@ -2187,7 +2184,6 @@ bool config_load_remap(void) else { RARCH_LOG("Remaps: no core-specific remap found at %s\n", core_path); - *settings->input.remapping_path= '\0'; input_remapping_set_defaults(); } @@ -2695,8 +2691,6 @@ bool config_save_file(const char *path) settings->cache_directory); config_set_path(conf, "input_remapping_directory", settings->input_remapping_directory); - config_set_path(conf, "input_remapping_path", - settings->input.remapping_path); config_set_path(conf, "resampler_directory", settings->resampler_directory); config_set_string(conf, "audio_resampler", settings->audio.resampler); diff --git a/configuration.h b/configuration.h index 82342d32ae..31f8a27f62 100644 --- a/configuration.h +++ b/configuration.h @@ -256,8 +256,6 @@ typedef struct settings bool input_descriptor_label_show; bool input_descriptor_hide_unbound; - char remapping_path[PATH_MAX_LENGTH]; - unsigned menu_toggle_gamepad_combo; bool back_as_menu_toggle_enable; diff --git a/cores/libretro-imageviewer/image_core.c b/cores/libretro-imageviewer/image_core.c index e34b85d338..edd02bb84b 100644 --- a/cores/libretro-imageviewer/image_core.c +++ b/cores/libretro-imageviewer/image_core.c @@ -9,10 +9,6 @@ #include #include -#ifdef HAVE_THREADS -#include -#endif - #define STB_IMAGE_IMPLEMENTATION #ifdef RARCH_INTERNAL @@ -42,6 +38,7 @@ static retro_input_state_t IMAGE_CORE_PREFIX(input_state_cb); static retro_audio_sample_batch_t IMAGE_CORE_PREFIX(audio_batch_cb); static retro_environment_t IMAGE_CORE_PREFIX(environ_cb); +static bool process_new_image; static uint32_t* image_buffer; static int image_width; static int image_height; @@ -49,17 +46,6 @@ static bool image_uploaded; static bool slideshow_enable; struct string_list *file_list; -#ifdef HAVE_THREADS -static async_job_t *imageviewer_jobs; - -#if 0 -static int imageviewer_async_job_add(async_task_t task, void *payload) -{ - return async_job_add(imageviewer_jobs, task, payload); -} -#endif -#endif - #if 0 #define DUPE_TEST #endif @@ -103,9 +89,6 @@ void IMAGE_CORE_PREFIX(retro_init)(void) image_width = 0; image_height = 0; -#ifdef HAVE_THREADS - imageviewer_jobs = async_job_new(); -#endif } void IMAGE_CORE_PREFIX(retro_deinit)(void) @@ -115,11 +98,6 @@ void IMAGE_CORE_PREFIX(retro_deinit)(void) image_buffer = NULL; image_width = 0; image_height = 0; - -#ifdef HAVE_THREADS - async_job_free(imageviewer_jobs); - imageviewer_jobs = NULL; -#endif } void IMAGE_CORE_PREFIX(retro_set_environment)(retro_environment_t cb) @@ -193,12 +171,11 @@ void IMAGE_CORE_PREFIX(retro_cheat_set)(unsigned a, bool b, const char * c) { } -static bool imageviewer_load(const char *path, uint32_t *buf, int image_index) +static bool imageviewer_load(const char *path, int image_index) { int comp; - struct retro_system_av_info info; - uint32_t *end = NULL; - if (image_buffer) free(image_buffer); + if (image_buffer) + free(image_buffer); image_buffer = (uint32_t*)stbi_load( path, @@ -207,30 +184,17 @@ static bool imageviewer_load(const char *path, uint32_t *buf, int image_index) &comp, 4); - /* RGBA > XRGB8888 */ - buf = &image_buffer[0]; - - if (!buf) + if (!image_buffer) return false; - end = buf + (image_width*image_height*sizeof(uint32_t))/4; - while(buf < end) - { - uint32_t pixel = *buf; - *buf = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff); - buf++; - } + process_new_image = true; - IMAGE_CORE_PREFIX(retro_get_system_av_info)(&info); - - IMAGE_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry); return true; } bool IMAGE_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) { - uint32_t *buf = NULL; enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888; char *dir = strdup(info->path); @@ -251,7 +215,7 @@ bool IMAGE_CORE_PREFIX(retro_load_game)(const struct retro_game_info *info) return false; } - if (!imageviewer_load(info->path, buf, 0)) + if (!imageviewer_load(info->path, 0)) return false; return true; @@ -289,7 +253,6 @@ size_t IMAGE_CORE_PREFIX(retro_get_memory_size)(unsigned id) void IMAGE_CORE_PREFIX(retro_run)(void) { - uint32_t *buf = NULL; bool first_image = false; bool last_image = false; bool backwards_image = false; @@ -387,12 +350,33 @@ void IMAGE_CORE_PREFIX(retro_run)(void) if (load_image) { - if (!imageviewer_load(file_list->elems[image_index].data, buf, image_index)) + if (!imageviewer_load(file_list->elems[image_index].data, image_index)) { IMAGE_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SHUTDOWN, NULL); } } + if (process_new_image) + { + /* RGBA > XRGB8888 */ + struct retro_system_av_info info; + uint32_t *buf = &image_buffer[0]; + uint32_t *end = buf + (image_width*image_height*sizeof(uint32_t))/4; + + while(buf < end) + { + uint32_t pixel = *buf; + *buf = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff); + buf++; + } + + IMAGE_CORE_PREFIX(retro_get_system_av_info)(&info); + + IMAGE_CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry); + + process_new_image = false; + } + #ifdef DUPE_TEST if (!image_uploaded) { diff --git a/cores/libretro-test-vulkan/libretro-test.c b/cores/libretro-test-vulkan/libretro-test.c index ac1b649577..b90bc46172 100644 --- a/cores/libretro-test-vulkan/libretro-test.c +++ b/cores/libretro-test-vulkan/libretro-test.c @@ -178,10 +178,10 @@ static void vulkan_test_render(void) update_ubo(); VkCommandBuffer cmd = vk.cmd[vk.index]; - vkResetCommandPool(vulkan->device, vk.cmd_pool[vk.index], 0); VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkResetCommandBuffer(cmd, 0); vkBeginCommandBuffer(cmd, &begin_info); VkImageMemoryBarrier prepare_rendering = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; @@ -548,6 +548,7 @@ static void init_swapchain(void) vkAllocateMemory(device, &alloc, NULL, &vk.image_memory[i]); vkBindImageMemory(device, vk.images[i].create_info.image, vk.image_memory[i], 0); + vk.images[i].create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vk.images[i].create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; vk.images[i].create_info.format = VK_FORMAT_R8G8B8A8_UNORM; vk.images[i].create_info.subresourceRange.baseMipLevel = 0; @@ -582,6 +583,7 @@ static void init_command(void) VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; pool_info.queueFamilyIndex = vulkan->queue_index; + pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; for (unsigned i = 0; i < vk.num_swapchain_images; i++) { diff --git a/frontend/frontend.c b/frontend/frontend.c index 33ee3c3877..6fa0a981d0 100644 --- a/frontend/frontend.c +++ b/frontend/frontend.c @@ -104,7 +104,9 @@ int rarch_main(int argc, char *argv[], void *data) char *fullpath = NULL; rarch_system_info_t *system = NULL; void *args = (void*)data; +#ifndef HAVE_MAIN int ret = 0; +#endif rarch_ctl(RARCH_CTL_PREINIT, NULL); diff --git a/gfx/common/egl_common.c b/gfx/common/egl_common.c index b6f432c1a8..2c8e2ba209 100644 --- a/gfx/common/egl_common.c +++ b/gfx/common/egl_common.c @@ -25,7 +25,6 @@ volatile sig_atomic_t g_egl_quit; bool g_egl_inited; -enum gfx_ctx_api g_egl_api; unsigned g_egl_major = 0; unsigned g_egl_minor = 0; @@ -102,7 +101,6 @@ void egl_destroy(void *data) egl->dpy = EGL_NO_DISPLAY; egl->config = 0; g_egl_quit = 0; - egl->api = GFX_CTX_NONE; g_egl_inited = false; } @@ -209,7 +207,6 @@ bool egl_init_context(void *data, NativeDisplayType display, if (!eglChooseConfig(egl->dpy, attrib_ptr, &egl->config, 1, n) || *n != 1) return false; - egl->api = g_egl_api; egl->major = g_egl_major; egl->minor = g_egl_minor; diff --git a/gfx/common/egl_common.h b/gfx/common/egl_common.h index b1beb9b03a..eaee0b1e5d 100644 --- a/gfx/common/egl_common.h +++ b/gfx/common/egl_common.h @@ -53,7 +53,6 @@ typedef struct unsigned major; unsigned minor; - enum gfx_ctx_api api; /* egl "private" */ bool use_hw_ctx; @@ -64,7 +63,6 @@ extern bool g_egl_inited; /* bind_api is called before init so we need these, please * try no to use them outside of bind_api() and init() */ -extern enum gfx_ctx_api g_egl_api; extern unsigned g_egl_major; extern unsigned g_egl_minor; diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index dad24c7442..a8950a49f5 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -86,6 +86,48 @@ void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *texture) vkMapMemory(device, texture->memory, texture->offset, texture->size, 0, &texture->mapped); } +void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd, + struct vk_texture *dynamic, + struct vk_texture *staging) +{ + VkImageCopy region; + retro_assert(dynamic->type == VULKAN_TEXTURE_DYNAMIC); + retro_assert(staging->type == VULKAN_TEXTURE_STAGING); + + vulkan_transition_texture(vk, staging); + + /* We don't have to sync against previous TRANSFER, since we observed the completion + * by fences. If we have a single texture_optimal, we would need to sync against + * previous transfers to avoid races. + * + * We would also need to optionally maintain extra textures due to changes in resolution, + * so this seems like the sanest and simplest solution. */ + vulkan_image_layout_transition(vk, vk->cmd, dynamic->image, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 0, VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); + + memset(®ion, 0, sizeof(region)); + region.extent.width = dynamic->width; + region.extent.height = dynamic->height; + region.extent.depth = 1; + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.layerCount = 1; + region.dstSubresource = region.srcSubresource; + + vkCmdCopyImage(vk->cmd, + staging->image, VK_IMAGE_LAYOUT_GENERAL, + dynamic->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion); + + vulkan_image_layout_transition(vk, vk->cmd, dynamic->image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + #ifdef VULKAN_DEBUG_TEXTURE_ALLOC static VkImage vk_images[4 * 1024]; static unsigned vk_count; @@ -131,70 +173,126 @@ struct vk_texture vulkan_create_texture(vk_t *vk, VkFormat format, const void *initial, const VkComponentMapping *swizzle, enum vk_texture_type type) { - /* TODO: Evaluate how we should do texture uploads on discrete cards optimally. - * For integrated GPUs, using linear texture is highly desirable to avoid extra copies, but - * we might need to take a DMA transfer with block interleave on desktop GPUs. - * - * Also, Vulkan drivers are not required to support sampling from linear textures - * (only TRANSFER), but seems to work fine on GPUs I've tested so far. */ - - VkDevice device = vk->context->device; struct vk_texture tex; - VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; - - VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; - VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT }; VkMemoryRequirements mem_reqs; VkSubresourceLayout layout; - - if (type == VULKAN_TEXTURE_STATIC && !initial) - retro_assert(0 && "Static textures must have initial data.\n"); + VkDevice device = vk->context->device; + VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; + VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + VkImageSubresource subresource = { VK_IMAGE_ASPECT_COLOR_BIT }; + VkCommandBufferAllocateInfo cmd_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; memset(&tex, 0, sizeof(tex)); - info.imageType = VK_IMAGE_TYPE_2D; - info.format = format; - info.extent.width = width; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = format; + info.extent.width = width; info.extent.height = height; - info.extent.depth = 1; - info.mipLevels = 1; - info.arrayLayers = 1; + info.extent.depth = 1; + info.mipLevels = 1; + info.arrayLayers = 1; info.samples = VK_SAMPLE_COUNT_1_BIT; - info.tiling = type != VULKAN_TEXTURE_STATIC ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; - info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - if (type == VULKAN_TEXTURE_STATIC) - info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if (type == VULKAN_TEXTURE_READBACK) - info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - /* We'll transition this on first use for streamed textures. */ - info.initialLayout = type == VULKAN_TEXTURE_STREAMED ? - VK_IMAGE_LAYOUT_PREINITIALIZED : - VK_IMAGE_LAYOUT_UNDEFINED; + if (type == VULKAN_TEXTURE_STREAMED) + { + VkFormatProperties format_properties; + VkFormatFeatureFlags required = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + vkGetPhysicalDeviceFormatProperties(vk->context->gpu, format, &format_properties); + + if ((format_properties.linearTilingFeatures & required) != required) + { + RARCH_LOG("[Vulkan]: GPU does not support using linear images as textures. Falling back to copy path.\n"); + type = VULKAN_TEXTURE_STAGING; + } + } + + switch (type) + { + case VULKAN_TEXTURE_STATIC: + retro_assert(initial && "Static textures must have initial data.\n"); + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + break; + + case VULKAN_TEXTURE_DYNAMIC: + retro_assert(!initial && "Dynamic textures must not have initial data.\n"); + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + break; + + case VULKAN_TEXTURE_STREAMED: + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + info.tiling = VK_IMAGE_TILING_LINEAR; + info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + break; + + case VULKAN_TEXTURE_STAGING: + info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + info.tiling = VK_IMAGE_TILING_LINEAR; + info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + break; + + case VULKAN_TEXTURE_READBACK: + info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.tiling = VK_IMAGE_TILING_LINEAR; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + break; + } vkCreateImage(device, &info, NULL, &tex.image); #if 0 vulkan_track_alloc(tex.image); #endif - vkGetImageMemoryRequirements(device, tex.image, &mem_reqs); - alloc.allocationSize = mem_reqs.size; - if (type == VULKAN_TEXTURE_STATIC) + switch (type) { - alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties, - mem_reqs.memoryTypeBits, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + case VULKAN_TEXTURE_STATIC: + case VULKAN_TEXTURE_DYNAMIC: + alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties, + mem_reqs.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0); + break; + + default: + alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties, + mem_reqs.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + break; } - else + + /* If the texture is STREAMED and it's not DEVICE_LOCAL, we expect to hit a slower path, + * so fallback to copy path. */ + if (type == VULKAN_TEXTURE_STREAMED && + (vk->context->memory_properties.memoryTypes[alloc.memoryTypeIndex].propertyFlags & + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { + /* Recreate texture but for STAGING this time ... */ + RARCH_LOG("[Vulkan]: GPU supports linear images as textures, but not DEVICE_LOCAL. Falling back to copy path.\n"); + type = VULKAN_TEXTURE_STAGING; + vkDestroyImage(device, tex.image, NULL); + info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + vkCreateImage(device, &info, NULL, &tex.image); + vkGetImageMemoryRequirements(device, tex.image, &mem_reqs); + alloc.allocationSize = mem_reqs.size; alloc.memoryTypeIndex = vulkan_find_memory_type_fallback(&vk->context->memory_properties, mem_reqs.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); } /* We're not reusing the objects themselves. */ @@ -213,7 +311,7 @@ struct vk_texture vulkan_create_texture(vk_t *vk, old->memory_size >= mem_reqs.size && old->memory_type == alloc.memoryTypeIndex) { - tex.memory = old->memory; + tex.memory = old->memory; tex.memory_size = old->memory_size; tex.memory_type = old->memory_type; @@ -237,17 +335,17 @@ struct vk_texture vulkan_create_texture(vk_t *vk, vkBindImageMemory(device, tex.image, tex.memory, 0); - view.image = tex.image; - view.viewType = VK_IMAGE_VIEW_TYPE_2D; - view.format = format; + view.image = tex.image; + view.viewType = VK_IMAGE_VIEW_TYPE_2D; + view.format = format; if (swizzle) - view.components = *swizzle; + view.components = *swizzle; else { - view.components.r = VK_COMPONENT_SWIZZLE_R; - view.components.g = VK_COMPONENT_SWIZZLE_G; - view.components.b = VK_COMPONENT_SWIZZLE_B; - view.components.a = VK_COMPONENT_SWIZZLE_A; + view.components.r = VK_COMPONENT_SWIZZLE_R; + view.components.g = VK_COMPONENT_SWIZZLE_G; + view.components.b = VK_COMPONENT_SWIZZLE_B; + view.components.a = VK_COMPONENT_SWIZZLE_A; } view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view.subresourceRange.levelCount = 1; @@ -258,26 +356,27 @@ struct vk_texture vulkan_create_texture(vk_t *vk, vkGetImageSubresourceLayout(device, tex.image, &subresource, &layout); tex.stride = layout.rowPitch; tex.offset = layout.offset; - tex.size = layout.size; + tex.size = layout.size; tex.layout = info.initialLayout; - tex.width = width; + tex.width = width; tex.height = height; tex.format = format; + tex.type = type; - if (initial && type == VULKAN_TEXTURE_STREAMED) + if (initial && (type == VULKAN_TEXTURE_STREAMED || type == VULKAN_TEXTURE_STAGING)) { - unsigned bpp = vulkan_format_to_bpp(tex.format); - unsigned stride = tex.width * bpp; unsigned x, y; - uint8_t *dst; - const uint8_t *src; - void *ptr; + uint8_t *dst = NULL; + const uint8_t *src = NULL; + void *ptr = NULL; + unsigned bpp = vulkan_format_to_bpp(tex.format); + unsigned stride = tex.width * bpp; vkMapMemory(device, tex.memory, tex.offset, tex.size, 0, &ptr); - dst = (uint8_t*)ptr; - src = (const uint8_t*)initial; + dst = (uint8_t*)ptr; + src = (const uint8_t*)initial; for (y = 0; y < tex.height; y++, dst += tex.stride, src += stride) memcpy(dst, src, width * bpp); @@ -285,22 +384,18 @@ struct vk_texture vulkan_create_texture(vk_t *vk, } else if (initial && type == VULKAN_TEXTURE_STATIC) { - VkCommandBufferAllocateInfo info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; - VkCommandBufferBeginInfo begin_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; - VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; VkImageCopy region; - VkCommandBuffer staging; unsigned bpp = vulkan_format_to_bpp(tex.format); struct vk_texture tmp = vulkan_create_texture(vk, NULL, - width, height, format, initial, NULL, VULKAN_TEXTURE_STREAMED); + width, height, format, initial, NULL, VULKAN_TEXTURE_STAGING); - info.commandPool = vk->staging_pool; - info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - info.commandBufferCount = 1; - vkAllocateCommandBuffers(vk->context->device, &info, &staging); + cmd_info.commandPool = vk->staging_pool; + cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmd_info.commandBufferCount = 1; + 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); vulkan_image_layout_transition(vk, staging, tmp.image, @@ -316,12 +411,12 @@ struct vk_texture vulkan_create_texture(vk_t *vk, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); memset(®ion, 0, sizeof(region)); - region.extent.width = width; - region.extent.height = height; - region.extent.depth = 1; + region.extent.width = width; + region.extent.height = height; + region.extent.depth = 1; region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.srcSubresource.layerCount = 1; - region.dstSubresource = region.srcSubresource; + region.dstSubresource = region.srcSubresource; vkCmdCopyImage(staging, tmp.image, VK_IMAGE_LAYOUT_GENERAL, @@ -329,19 +424,23 @@ struct vk_texture vulkan_create_texture(vk_t *vk, 1, ®ion); vulkan_image_layout_transition(vk, staging, tex.image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT); vkEndCommandBuffer(staging); submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &staging; + submit_info.pCommandBuffers = &staging; slock_lock(vk->context->queue_lock); vkQueueSubmit(vk->context->queue, 1, &submit_info, VK_NULL_HANDLE); - /* TODO: Very crude, but texture uploads only happen during init, - * so waiting for GPU to complete transfer and blocking isn't a big deal. */ + + /* TODO: Very crude, but texture uploads only happen + * during init, so waiting for GPU to complete transfer + * and blocking isn't a big deal. */ vkQueueWaitIdle(vk->context->queue); slock_unlock(vk->context->queue_lock); @@ -377,33 +476,34 @@ static void vulkan_write_quad_descriptors(VkDevice device, VkDescriptorImageInfo image_info; VkDescriptorBufferInfo buffer_info; - image_info.sampler = sampler; - image_info.imageView = texture->view; + image_info.sampler = sampler; + image_info.imageView = texture->view; image_info.imageLayout = texture->layout; - buffer_info.buffer = buffer; - buffer_info.offset = offset; - buffer_info.range = range; + buffer_info.buffer = buffer; + buffer_info.offset = offset; + buffer_info.range = range; - write.dstSet = set; - write.dstBinding = 0; - write.descriptorCount = 1; - write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write.pBufferInfo = &buffer_info; + write.dstSet = set; + write.dstBinding = 0; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + write.pBufferInfo = &buffer_info; vkUpdateDescriptorSets(device, 1, &write, 0, NULL); - write.dstSet = set; - write.dstBinding = 1; - write.descriptorCount = 1; - write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write.pImageInfo = &image_info; + write.dstSet = set; + write.dstBinding = 1; + write.descriptorCount = 1; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.pImageInfo = &image_info; vkUpdateDescriptorSets(device, 1, &write, 0, NULL); } void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture) { /* Transition to GENERAL layout for linear streamed textures. - * We're using linear textures here, so only GENERAL layout is supported. + * We're using linear textures here, so only + * GENERAL layout is supported. */ if (texture->layout == VK_IMAGE_LAYOUT_PREINITIALIZED) { @@ -420,7 +520,9 @@ static void vulkan_check_dynamic_state(vk_t *vk) { if (vk->tracker.dirty & VULKAN_DIRTY_DYNAMIC_BIT) { - const VkRect2D sci = {{ vk->vp.x, vk->vp.y }, { vk->vp.width, vk->vp.height }}; + const VkRect2D sci = { + { vk->vp.x, vk->vp.y }, + { vk->vp.width, vk->vp.height }}; vkCmdSetViewport(vk->cmd, 0, 1, &vk->vk_vp); vkCmdSetScissor(vk->cmd, 0, 1, &sci); @@ -434,7 +536,8 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call) 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; /* Changing pipeline invalidates dynamic state. */ @@ -447,9 +550,9 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call) { VkDescriptorSet set; - if (memcmp(call->mvp, &vk->tracker.mvp, sizeof(*call->mvp)) || - call->texture->view != vk->tracker.view || - call->sampler != vk->tracker.sampler) + if (memcmp(call->mvp, &vk->tracker.mvp, sizeof(*call->mvp)) + || (call->texture->view != vk->tracker.view) + || (call->sampler != vk->tracker.sampler)) { /* Upload UBO */ struct vk_buffer_range range; @@ -458,7 +561,8 @@ void vulkan_draw_triangles(vk_t *vk, const struct vk_draw_triangles *call) return; 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, set, range.buffer, @@ -491,11 +595,12 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad) 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; /* Changing pipeline invalidates dynamic state. */ - vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT; + vk->tracker.dirty |= VULKAN_DIRTY_DYNAMIC_BIT; } vulkan_check_dynamic_state(vk); @@ -508,9 +613,9 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad) sizeof(*quad->mvp), &range)) return; - if (memcmp(quad->mvp, &vk->tracker.mvp, sizeof(*quad->mvp)) || - quad->texture->view != vk->tracker.view || - quad->sampler != vk->tracker.sampler) + if (memcmp(quad->mvp, &vk->tracker.mvp, sizeof(*quad->mvp)) + || quad->texture->view != vk->tracker.view + || quad->sampler != vk->tracker.sampler) { /* Upload UBO */ struct vk_buffer_range range; @@ -519,7 +624,9 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad) return; 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, set, range.buffer, @@ -532,9 +639,9 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad) vk->pipelines.layout, 0, 1, &set, 0, NULL); - vk->tracker.view = quad->texture->view; + vk->tracker.view = quad->texture->view; vk->tracker.sampler = quad->sampler; - vk->tracker.mvp = *quad->mvp; + vk->tracker.mvp = *quad->mvp; } } @@ -558,20 +665,25 @@ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad) vkCmdDraw(vk->cmd, 6, 1, 0, 0); } -void vulkan_image_layout_transition(vk_t *vk, VkCommandBuffer cmd, VkImage image, - VkImageLayout old_layout, VkImageLayout new_layout, - VkAccessFlags srcAccess, VkAccessFlags dstAccess, - VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages) +void vulkan_image_layout_transition( + vk_t *vk, + VkCommandBuffer cmd, VkImage image, + VkImageLayout old_layout, + VkImageLayout new_layout, + VkAccessFlags srcAccess, + VkAccessFlags dstAccess, + VkPipelineStageFlags srcStages, + VkPipelineStageFlags dstStages) { VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; - barrier.srcAccessMask = srcAccess; - barrier.dstAccessMask = dstAccess; - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; + barrier.srcAccessMask = srcAccess; + barrier.dstAccessMask = dstAccess; + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.layerCount = 1; @@ -591,25 +703,28 @@ struct vk_buffer vulkan_create_buffer(const struct vulkan_context *context, struct vk_buffer buffer; VkMemoryRequirements mem_reqs; VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - info.size = size; - info.usage = usage; + info.size = size; + info.usage = usage; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateBuffer(context->device, &info, NULL, &buffer.buffer); vkGetBufferMemoryRequirements(context->device, buffer.buffer, &mem_reqs); - alloc.allocationSize = mem_reqs.size; - alloc.memoryTypeIndex = vulkan_find_memory_type(&context->memory_properties, + alloc.allocationSize = mem_reqs.size; + alloc.memoryTypeIndex = vulkan_find_memory_type( + &context->memory_properties, mem_reqs.memoryTypeBits, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); vkAllocateMemory(context->device, &alloc, NULL, &buffer.memory); vkBindBufferMemory(context->device, buffer.buffer, buffer.memory, 0); buffer.size = alloc.allocationSize; - vkMapMemory(context->device, buffer.memory, 0, buffer.size, 0, &buffer.mapped); + vkMapMemory(context->device, + buffer.memory, 0, buffer.size, 0, &buffer.mapped); return buffer; } @@ -621,14 +736,18 @@ void vulkan_destroy_buffer(VkDevice device, struct vk_buffer *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) { unsigned i; - VkDescriptorPoolCreateInfo pool_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; - VkDescriptorSetAllocateInfo alloc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; + VkDescriptorPoolCreateInfo pool_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; + VkDescriptorSetAllocateInfo alloc_info = { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; - struct vk_descriptor_pool *pool = (struct vk_descriptor_pool*)calloc(1, sizeof(*pool)); + struct vk_descriptor_pool *pool = + (struct vk_descriptor_pool*)calloc(1, sizeof(*pool)); if (!pool) return NULL; @@ -648,7 +767,8 @@ static struct vk_descriptor_pool *vulkan_alloc_descriptor_pool(VkDevice device, 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) return manager->current->sets[manager->count++]; @@ -656,7 +776,7 @@ VkDescriptorSet vulkan_descriptor_manager_alloc(VkDevice device, struct vk_descr while (manager->current->next) { manager->current = manager->current->next; - manager->count = 0; + manager->count = 0; return manager->current->sets[manager->count++]; } @@ -664,7 +784,7 @@ VkDescriptorSet vulkan_descriptor_manager_alloc(VkDevice device, struct vk_descr retro_assert(manager->current->next); manager->current = manager->current->next; - manager->count = 0; + manager->count = 0; return manager->current->sets[manager->count++]; } @@ -674,22 +794,26 @@ void vulkan_descriptor_manager_restart(struct vk_descriptor_manager *manager) manager->count = 0; } -struct vk_descriptor_manager vulkan_create_descriptor_manager(VkDevice device, - const VkDescriptorPoolSize *sizes, unsigned num_sizes, VkDescriptorSetLayout set_layout) +struct vk_descriptor_manager vulkan_create_descriptor_manager( + VkDevice device, + const VkDescriptorPoolSize *sizes, + unsigned num_sizes, + VkDescriptorSetLayout set_layout) { struct vk_descriptor_manager manager; memset(&manager, 0, sizeof(manager)); retro_assert(num_sizes <= VULKAN_MAX_DESCRIPTOR_POOL_SIZES); memcpy(manager.sizes, sizes, num_sizes * sizeof(*sizes)); - manager.num_sizes = num_sizes; + manager.num_sizes = num_sizes; manager.set_layout = set_layout; - manager.head = vulkan_alloc_descriptor_pool(device, &manager); + manager.head = vulkan_alloc_descriptor_pool(device, &manager); retro_assert(manager.head); return manager; } -void vulkan_destroy_descriptor_manager(VkDevice device, struct vk_descriptor_manager *manager) +void vulkan_destroy_descriptor_manager(VkDevice device, + struct vk_descriptor_manager *manager) { struct vk_descriptor_pool *node = manager->head; @@ -697,7 +821,8 @@ void vulkan_destroy_descriptor_manager(VkDevice device, struct vk_descriptor_man { 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); free(node); @@ -713,26 +838,30 @@ static void vulkan_buffer_chain_step(struct vk_buffer_chain *chain) 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; if (next_offset <= chain->current->buffer.size) { - 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->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; } - else - return false; + + return false; } static struct vk_buffer_node *vulkan_buffer_chain_alloc_node( const struct vulkan_context *context, size_t size, VkBufferUsageFlags usage) { - struct vk_buffer_node *node = (struct vk_buffer_node*)calloc(1, sizeof(*node)); + struct vk_buffer_node *node = (struct vk_buffer_node*) + calloc(1, sizeof(*node)); if (!node) return NULL; @@ -744,7 +873,8 @@ struct vk_buffer_chain vulkan_buffer_chain_init(VkDeviceSize block_size, VkDeviceSize alignment, VkBufferUsageFlags usage) { - struct vk_buffer_chain chain = { block_size, alignment, 0, usage, NULL, NULL }; + struct vk_buffer_chain chain = { + block_size, alignment, 0, usage, NULL, NULL }; return chain; } @@ -755,7 +885,8 @@ void vulkan_buffer_chain_discard(struct vk_buffer_chain *chain) } bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, - struct vk_buffer_chain *chain, size_t size, struct vk_buffer_range *range) + struct vk_buffer_chain *chain, + size_t size, struct vk_buffer_range *range) { if (!chain->head) { @@ -781,7 +912,8 @@ bool vulkan_buffer_chain_alloc(const struct vulkan_context *context, } /* 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) size = chain->block_size; @@ -1224,7 +1356,7 @@ void vulkan_acquire_next_image(gfx_ctx_vulkan_data_t *vk) VkFence *next_fence; VkSemaphoreCreateInfo sem_info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; - VkFenceCreateInfo info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; + VkFenceCreateInfo info = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; vkCreateFence(vk->context.device, &info, NULL, &fence); @@ -1287,7 +1419,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, if (format_count == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { - format = formats[0]; + format = formats[0]; format.format = VK_FORMAT_B8G8R8A8_UNORM; } else @@ -1314,6 +1446,8 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, /* Limit latency. */ if (desired_swapchain_images > 3) desired_swapchain_images = 3; + if (desired_swapchain_images < surface_properties.minImageCount) + desired_swapchain_images = surface_properties.minImageCount; if ((surface_properties.maxImageCount > 0) && (desired_swapchain_images > surface_properties.maxImageCount)) diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 2288fc96be..e98d339f7a 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -52,11 +52,39 @@ #include -#include -#include +#ifndef VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL +#define VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL 1024 +#endif + +typedef struct VkDmaBufImageCreateInfo_ +{ + VkStructureType sType; /* Must be VK_STRUCTURE_TYPE_DMA_BUF_IMAGE_CREATE_INFO_INTEL */ + const void* pNext; /* Pointer to next structure. */ + int fd; + VkFormat format; + VkExtent3D extent; /* Depth must be 1 */ + uint32_t strideInBytes; +} VkDmaBufImageCreateInfo; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateDmaBufImageINTEL)(VkDevice device, + const VkDmaBufImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, VkDeviceMemory* pMem, VkImage* pImage); + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDmaBufImageINTEL( + VkDevice _device, + const VkDmaBufImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMem, + VkImage* pImage); + +#include #include #include -#include "boolean.h" +#include +#include +#include +#include + #include "../../driver.h" #include "../../performance.h" #include "../../libretro.h" @@ -66,13 +94,25 @@ #include "../video_context_driver.h" #include "libretro_vulkan.h" #include "../drivers_shader/shader_vulkan.h" -#include -#include enum vk_texture_type { + /* We will use the texture as a sampled linear texture. */ VULKAN_TEXTURE_STREAMED = 0, + + /* We will use the texture as a linear texture, but only + * for copying to a DYNAMIC texture. */ + VULKAN_TEXTURE_STAGING, + + /* We will use the texture as an optimally tiled texture, + * and we will update the texture by copying from STAGING + * textures. */ + VULKAN_TEXTURE_DYNAMIC, + + /* We will upload content once. */ VULKAN_TEXTURE_STATIC, + + /* We will use the texture for reading back transfers from GPU. */ VULKAN_TEXTURE_READBACK }; @@ -118,10 +158,14 @@ typedef struct gfx_ctx_vulkan_data { vulkan_context_t context; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR + fpGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR + fpGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR + fpGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR + fpGetPhysicalDeviceSurfacePresentModesKHR; PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR; PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR; PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR; @@ -188,6 +232,7 @@ struct vk_texture uint32_t memory_type; VkImageLayout layout; + enum vk_texture_type type; bool default_smooth; }; @@ -259,6 +304,7 @@ struct vk_per_frame { struct vk_image backbuffer; struct vk_texture texture; + struct vk_texture texture_optimal; struct vk_buffer_chain vbo; struct vk_buffer_chain ubo; struct vk_descriptor_manager descriptor_manager; @@ -336,6 +382,7 @@ typedef struct vk struct { VkPipeline alpha_blend; + VkPipeline font; VkDescriptorSetLayout set_layout; VkPipelineLayout layout; VkPipelineCache cache; @@ -351,6 +398,9 @@ typedef struct vk struct { struct vk_texture textures[VULKAN_MAX_SWAPCHAIN_IMAGES]; + struct vk_texture textures_optimal[VULKAN_MAX_SWAPCHAIN_IMAGES]; + bool dirty[VULKAN_MAX_SWAPCHAIN_IMAGES]; + float alpha; unsigned last_index; bool enable; @@ -420,6 +470,10 @@ void vulkan_transition_texture(vk_t *vk, struct vk_texture *texture); void vulkan_map_persistent_texture(VkDevice device, struct vk_texture *tex); void vulkan_destroy_texture(VkDevice device, struct vk_texture *tex); +void vulkan_copy_staging_to_dynamic(vk_t *vk, VkCommandBuffer cmd, + struct vk_texture *dynamic, + struct vk_texture *staging); + /* VBO will be written to here. */ void vulkan_draw_quad(vk_t *vk, const struct vk_draw_quad *quad); @@ -428,7 +482,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_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, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkPipelineStageFlags srcStages, VkPipelineStageFlags dstStages); @@ -470,8 +525,8 @@ static INLINE void vulkan_write_quad_vbo(struct vk_vertex *pv, for (i = 0; i < 6; i++) { - pv[i].x = x + strip[2 * i + 0] * width; - pv[i].y = y + strip[2 * i + 1] * height; + pv[i].x = x + strip[2 * i + 0] * width; + pv[i].y = y + strip[2 * i + 1] * height; pv[i].tex_x = tex_x + strip[2 * i + 0] * tex_width; pv[i].tex_y = tex_y + strip[2 * i + 1] * tex_height; pv[i].color = *color; diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 31a65a3898..b5e25a514c 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2804,11 +2804,12 @@ static void *gl_init(const video_info_t *video, const input_driver_t **input, vo } { + unsigned minimum; video_shader_ctx_texture_t texture_info; video_shader_driver_ctl(SHADER_CTL_GET_PREV_TEXTURES, &texture_info); - unsigned minimum = texture_info.id; + minimum = texture_info.id; gl->textures = max(minimum + 1, gl->textures); } diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 129ba55d09..7de2c4ae1e 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -16,6 +16,7 @@ #include "../common/vulkan_common.h" #include "vulkan_shaders/alpha_blend.vert.inc" #include "vulkan_shaders/alpha_blend.frag.inc" +#include "vulkan_shaders/font.frag.inc" #include #include @@ -301,7 +302,6 @@ static void vulkan_init_pipelines(vk_t *vk) pipe.renderPass = vk->render_pass; pipe.layout = vk->pipelines.layout; - /* Alpha-blended pipeline. */ module_info.codeSize = alpha_blend_vert_spv_len; module_info.pCode = (const uint32_t*)alpha_blend_vert_spv; shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; @@ -309,13 +309,6 @@ static void vulkan_init_pipelines(vk_t *vk) vkCreateShaderModule(vk->context->device, &module_info, NULL, &shader_stages[0].module); - module_info.codeSize = alpha_blend_frag_spv_len; - module_info.pCode = (const uint32_t*)alpha_blend_frag_spv; - shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].pName = "main"; - vkCreateShaderModule(vk->context->device, - &module_info, NULL, &shader_stages[1].module); - blend_attachment.blendEnable = true; blend_attachment.colorWriteMask = 0xf; blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; @@ -323,7 +316,27 @@ static void vulkan_init_pipelines(vk_t *vk) blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + + /* Glyph pipeline */ + module_info.codeSize = font_frag_spv_len; + module_info.pCode = (const uint32_t*)font_frag_spv; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].pName = "main"; + vkCreateShaderModule(vk->context->device, + &module_info, NULL, &shader_stages[1].module); + + vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache, + 1, &pipe, NULL, &vk->pipelines.font); + vkDestroyShaderModule(vk->context->device, shader_stages[1].module, NULL); + + /* Alpha-blended pipeline. */ + module_info.codeSize = alpha_blend_frag_spv_len; + module_info.pCode = (const uint32_t*)alpha_blend_frag_spv; + shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shader_stages[1].pName = "main"; + vkCreateShaderModule(vk->context->device, + &module_info, NULL, &shader_stages[1].module); vkCreateGraphicsPipelines(vk->context->device, vk->pipelines.cache, 1, &pipe, NULL, &vk->pipelines.alpha_blend); @@ -461,6 +474,13 @@ static void vulkan_init_textures(vk_t *vk) NULL, NULL, VULKAN_TEXTURE_STREAMED); vulkan_map_persistent_texture(vk->context->device, &vk->swapchain[i].texture); + + if (vk->swapchain[i].texture.type == VULKAN_TEXTURE_STAGING) + { + vk->swapchain[i].texture_optimal = vulkan_create_texture(vk, NULL, + vk->tex_w, vk->tex_h, vk->tex_fmt, + NULL, NULL, VULKAN_TEXTURE_DYNAMIC); + } } } } @@ -471,9 +491,12 @@ static void vulkan_deinit_textures(vk_t *vk) unsigned i; for (i = 0; i < vk->num_swapchain_images; i++) + { if (vk->swapchain[i].texture.memory != VK_NULL_HANDLE) - vulkan_destroy_texture(vk->context->device, - &vk->swapchain[i].texture); + vulkan_destroy_texture(vk->context->device, &vk->swapchain[i].texture); + if (vk->swapchain[i].texture_optimal.memory != VK_NULL_HANDLE) + vulkan_destroy_texture(vk->context->device, &vk->swapchain[i].texture_optimal); + } } static void vulkan_deinit_command_buffers(vk_t *vk) @@ -503,6 +526,7 @@ static void vulkan_deinit_pipelines(vk_t *vk) unsigned i; vulkan_deinit_pipeline_layout(vk); vkDestroyPipeline(vk->context->device, vk->pipelines.alpha_blend, NULL); + vkDestroyPipeline(vk->context->device, vk->pipelines.font, NULL); for (i = 0; i < 4; i++) vkDestroyPipeline(vk->context->device, vk->display.pipelines[i], NULL); } @@ -671,9 +695,12 @@ static void vulkan_deinit_menu(vk_t *vk) { unsigned i; for (i = 0; i < VULKAN_MAX_SWAPCHAIN_IMAGES; i++) + { if (vk->menu.textures[i].memory) - vulkan_destroy_texture(vk->context->device, - &vk->menu.textures[i]); + vulkan_destroy_texture(vk->context->device, &vk->menu.textures[i]); + if (vk->menu.textures_optimal[i].memory) + vulkan_destroy_texture(vk->context->device, &vk->menu.textures_optimal[i]); + } } static void vulkan_free(void *data) @@ -1323,6 +1350,13 @@ static bool vulkan_frame(void *data, const void *frame, vulkan_buffer_chain_discard(&chain->vbo); vulkan_buffer_chain_discard(&chain->ubo); + /* Start recording the command buffer. */ + vk->cmd = chain->cmd; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkResetCommandBuffer(vk->cmd, 0); + vkBeginCommandBuffer(vk->cmd, &begin_info); + memset(&vk->tracker, 0, sizeof(vk->tracker)); + /* Upload texture */ retro_perf_start(©_frame); if (frame && !vk->hw.enable) @@ -1336,9 +1370,16 @@ static bool vulkan_frame(void *data, const void *frame, || chain->texture.height != frame_height) { chain->texture = vulkan_create_texture(vk, &chain->texture, - frame_width, frame_height, chain->texture.format, - NULL, NULL, VULKAN_TEXTURE_STREAMED); + frame_width, frame_height, chain->texture.format, NULL, NULL, + chain->texture_optimal.memory ? VULKAN_TEXTURE_STAGING : VULKAN_TEXTURE_STREAMED); vulkan_map_persistent_texture(vk->context->device, &chain->texture); + + if (chain->texture.type == VULKAN_TEXTURE_STAGING) + { + chain->texture_optimal = vulkan_create_texture(vk, &chain->texture_optimal, + frame_width, frame_height, chain->texture_optimal.format, + NULL, NULL, VULKAN_TEXTURE_DYNAMIC); + } } if (frame != chain->texture.mapped) @@ -1352,17 +1393,17 @@ static bool vulkan_frame(void *data, const void *frame, memcpy(dst, src, frame_width * bpp); } + /* If we have an optimal texture, copy to that now. */ + if (chain->texture_optimal.memory != VK_NULL_HANDLE) + { + vulkan_copy_staging_to_dynamic(vk, vk->cmd, + &chain->texture_optimal, &chain->texture); + } + vk->last_valid_index = frame_index; } retro_perf_stop(©_frame); - /* Start recording the command buffer. */ - vk->cmd = chain->cmd; - begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - vkResetCommandBuffer(vk->cmd, 0); - vkBeginCommandBuffer(vk->cmd, &begin_info); - memset(&vk->tracker, 0, sizeof(vk->tracker)); - /* Notify filter chain about the new sync index. */ vulkan_filter_chain_notify_sync_index(vk->filter_chain, frame_index); @@ -1399,9 +1440,11 @@ static bool vulkan_frame(void *data, const void *frame, } else { - struct vk_texture *tex = & - vk->swapchain[vk->last_valid_index].texture; - vulkan_transition_texture(vk, tex); + struct vk_texture *tex = &vk->swapchain[vk->last_valid_index].texture; + if (vk->swapchain[vk->last_valid_index].texture_optimal.memory != VK_NULL_HANDLE) + tex = &vk->swapchain[vk->last_valid_index].texture_optimal; + else + vulkan_transition_texture(vk, tex); input.view = tex->view; input.layout = tex->layout; @@ -1450,16 +1493,30 @@ static bool vulkan_frame(void *data, const void *frame, if (vk->menu.textures[vk->menu.last_index].image != VK_NULL_HANDLE) { struct vk_draw_quad quad; + struct vk_texture *optimal = &vk->menu.textures_optimal[vk->menu.last_index]; vulkan_set_viewport(vk, width, height, vk->menu.full_screen, false); quad.pipeline = vk->pipelines.alpha_blend; - quad.texture = &vk->menu.textures[vk->menu.last_index]; - quad.sampler = vk->samplers.linear; - quad.mvp = &vk->mvp_no_rot; - quad.color.r = 1.0f; - quad.color.g = 1.0f; - quad.color.b = 1.0f; - quad.color.a = vk->menu.alpha; + quad.texture = &vk->menu.textures[vk->menu.last_index]; + + if (optimal->memory != VK_NULL_HANDLE) + { + if (vk->menu.dirty[vk->menu.last_index]) + { + vulkan_copy_staging_to_dynamic(vk, vk->cmd, + optimal, + quad.texture); + vk->menu.dirty[vk->menu.last_index] = false; + } + quad.texture = optimal; + } + + quad.sampler = vk->samplers.linear; + quad.mvp = &vk->mvp_no_rot; + quad.color.r = 1.0f; + quad.color.g = 1.0f; + quad.color.b = 1.0f; + quad.color.a = vk->menu.alpha; vulkan_draw_quad(vk, &quad); } } @@ -1657,6 +1714,13 @@ static bool vulkan_get_current_sw_framebuffer(void *data, framebuffer->width, framebuffer->height, chain->texture.format, NULL, NULL, VULKAN_TEXTURE_STREAMED); vulkan_map_persistent_texture(vk->context->device, &chain->texture); + + if (chain->texture.type == VULKAN_TEXTURE_STAGING) + { + chain->texture_optimal = vulkan_create_texture(vk, &chain->texture_optimal, + framebuffer->width, framebuffer->height, chain->texture_optimal.format, + NULL, NULL, VULKAN_TEXTURE_DYNAMIC); + } } framebuffer->data = chain->texture.mapped; @@ -1690,9 +1754,10 @@ static void vulkan_set_texture_frame(void *data, { uint8_t *ptr; unsigned x, y; - vk_t *vk = (vk_t*)data; - unsigned index = vk->context->current_swapchain_index; - struct vk_texture *texture = &vk->menu.textures[index]; + vk_t *vk = (vk_t*)data; + unsigned index = vk->context->current_swapchain_index; + struct vk_texture *texture = &vk->menu.textures[index]; + struct vk_texture *texture_optimal = &vk->menu.textures_optimal[index]; const VkComponentMapping br_swizzle = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, @@ -1709,7 +1774,8 @@ static void vulkan_set_texture_frame(void *data, texture->memory ? texture : NULL, width, height, rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16, - NULL, rgb32 ? NULL : &br_swizzle, VULKAN_TEXTURE_STREAMED); + NULL, rgb32 ? NULL : &br_swizzle, + texture_optimal->memory ? VULKAN_TEXTURE_STAGING : VULKAN_TEXTURE_STREAMED); vkMapMemory(vk->context->device, texture->memory, texture->offset, texture->size, 0, (void**)&ptr); @@ -1723,6 +1789,18 @@ static void vulkan_set_texture_frame(void *data, vkUnmapMemory(vk->context->device, texture->memory); vk->menu.alpha = alpha; vk->menu.last_index = index; + + if (texture->type == VULKAN_TEXTURE_STAGING) + { + *texture_optimal = vulkan_create_texture(vk, + texture_optimal->memory ? texture_optimal : NULL, + width, height, + rgb32 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_B4G4R4A4_UNORM_PACK16, + NULL, rgb32 ? NULL : &br_swizzle, + VULKAN_TEXTURE_DYNAMIC); + } + + vk->menu.dirty[index] = true; } static void vulkan_set_texture_enable(void *data, bool state, bool full_screen) diff --git a/gfx/drivers/vulkan_shaders/font.frag b/gfx/drivers/vulkan_shaders/font.frag new file mode 100644 index 0000000000..8aacb6fa39 --- /dev/null +++ b/gfx/drivers/vulkan_shaders/font.frag @@ -0,0 +1,12 @@ +#version 310 es +precision highp float; +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in vec4 vColor; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 1) uniform highp sampler2D uTex; + +void main() +{ + // Workaround for early drivers which fail to apply swizzle in VkImageView. + FragColor = vec4(vColor.rgb, vColor.a * texture(uTex, vTexCoord).x); +} diff --git a/gfx/drivers/vulkan_shaders/font.frag.inc b/gfx/drivers/vulkan_shaders/font.frag.inc new file mode 100644 index 0000000000..4adb43b6df --- /dev/null +++ b/gfx/drivers/vulkan_shaders/font.frag.inc @@ -0,0 +1,80 @@ +unsigned char font_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x76, 0x43, 0x6f, 0x6c, + 0x6f, 0x72, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x75, 0x54, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x76, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, + 0x64, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +unsigned int font_frag_spv_len = 920; diff --git a/gfx/drivers_context/bbqnx_ctx.c b/gfx/drivers_context/bbqnx_ctx.c index d042391c71..ca7e04eb4a 100644 --- a/gfx/drivers_context/bbqnx_ctx.c +++ b/gfx/drivers_context/bbqnx_ctx.c @@ -315,8 +315,6 @@ static bool gfx_ctx_qnx_bind_api(void *data, (void)major; (void)minor; - g_egl_api = api; - return api == GFX_CTX_OPENGL_ES_API; } diff --git a/gfx/drivers_context/drm_egl_ctx.c b/gfx/drivers_context/drm_ctx.c similarity index 60% rename from gfx/drivers_context/drm_egl_ctx.c rename to gfx/drivers_context/drm_ctx.c index aa0b58347a..b6d2af75b1 100644 --- a/gfx/drivers_context/drm_egl_ctx.c +++ b/gfx/drivers_context/drm_ctx.c @@ -35,21 +35,35 @@ #include #include - +#include "../../verbosity.h" #include "../../driver.h" #include "../../runloop.h" #include "../common/drm_common.h" + +#ifdef HAVE_EGL #include "../common/egl_common.h" +#endif + +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) #include "../common/gl_common.h" +#endif #ifdef HAVE_CONFIG_H #include "../../config.h" #endif +#ifdef HAVE_OPENGLES + #ifndef EGL_OPENGL_ES3_BIT_KHR #define EGL_OPENGL_ES3_BIT_KHR 0x0040 #endif +#endif + +static volatile sig_atomic_t drm_quit = 0; + +static enum gfx_ctx_api drm_api; + static struct gbm_bo *g_bo; static struct gbm_bo *g_next_bo; static struct gbm_surface *g_gbm_surface; @@ -57,13 +71,16 @@ static struct gbm_device *g_gbm_dev; static bool waiting_for_flip; -typedef struct gfx_ctx_drm_egl_data +typedef struct gfx_ctx_drm_data { +#ifdef HAVE_EGL egl_ctx_data_t egl; - RFILE *g_drm; - unsigned g_fb_width; - unsigned g_fb_height; -} gfx_ctx_drm_egl_data_t; +#endif + RFILE *drm; + unsigned interval; + unsigned fb_width; + unsigned fb_height; +} gfx_ctx_drm_data_t; struct drm_fb { @@ -71,6 +88,24 @@ struct drm_fb uint32_t fb_id; }; +static void drm_sighandler(int sig) +{ + (void)sig; + drm_quit = 1; +} + +static void drm_install_sighandler(void) +{ + struct sigaction sa; + + sa.sa_sigaction = NULL; + sa.sa_handler = drm_sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data) { struct drm_fb *fb = (struct drm_fb*)data; @@ -97,7 +132,7 @@ static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) stride = gbm_bo_get_stride(bo); handle = gbm_bo_get_handle(bo).u32; - RARCH_LOG("[KMS/EGL]: New FB: %ux%u (stride: %u).\n", + RARCH_LOG("[KMS]: New FB: %ux%u (stride: %u).\n", width, height, stride); ret = drmModeAddFB(g_drm_fd, width, height, 24, 32, @@ -109,20 +144,21 @@ static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) return fb; error: - RARCH_ERR("[KMS/EGL]: Failed to create FB: %s\n", strerror(errno)); + RARCH_ERR("[KMS]: Failed to create FB: %s\n", strerror(errno)); free(fb); return NULL; } -static void gfx_ctx_drm_egl_swap_interval(void *data, unsigned interval) +static void gfx_ctx_drm_swap_interval(void *data, unsigned interval) { - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)data; - drm->egl.interval = interval; + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + drm->interval = interval; + if (interval > 1) - RARCH_WARN("[KMS/EGL]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); + RARCH_WARN("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); } -static void gfx_ctx_drm_egl_check_window(void *data, bool *quit, +static void gfx_ctx_drm_check_window(void *data, bool *quit, bool *resize, unsigned *width, unsigned *height, unsigned frame_count) { (void)data; @@ -131,11 +167,11 @@ static void gfx_ctx_drm_egl_check_window(void *data, bool *quit, (void)height; *resize = false; - *quit = g_egl_quit; + *quit = drm_quit; } -static void drm_egl_flip_handler(int fd, unsigned frame, +static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void *data) { static unsigned first_page_flip; @@ -152,7 +188,7 @@ static void drm_egl_flip_handler(int fd, unsigned frame, { unsigned missed = frame - last_page_flip - 1; if (missed) - RARCH_LOG("[KMS/EGL]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", + RARCH_LOG("[KMS]: Missed %u VBlank(s) (Frame: %u, DRM frame: %u).\n", missed, frame - first_page_flip, frame); } @@ -160,7 +196,7 @@ static void drm_egl_flip_handler(int fd, unsigned frame, *(bool*)data = false; } -static bool wait_flip(bool block) +static bool gfx_ctx_drm_wait_flip(bool block) { int timeout = 0; @@ -189,12 +225,11 @@ static bool wait_flip(bool block) return false; } -static bool queue_flip(void) +static bool gfx_ctx_drm_queue_flip(void) { struct drm_fb *fb = NULL; - - g_next_bo = gbm_surface_lock_front_buffer(g_gbm_surface); - fb = (struct drm_fb*)drm_fb_get_from_bo(g_next_bo); + g_next_bo = gbm_surface_lock_front_buffer(g_gbm_surface); + fb = (struct drm_fb*)drm_fb_get_from_bo(g_next_bo); if (drmModePageFlip(g_drm_fd, g_crtc_id, fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip) == 0) @@ -204,31 +239,43 @@ static bool queue_flip(void) return false; } -static void gfx_ctx_drm_egl_swap_buffers(void *data) +static void gfx_ctx_drm_swap_buffers(void *data) { - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)data; - egl_swap_buffers(data); + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + egl_swap_buffers(drm); +#endif + break; + default: + break; + } /* I guess we have to wait for flip to have taken * place before another flip can be queued up. * * If true, we are still waiting for a flip * (nonblocking mode, so just drop the frame). */ - if (wait_flip(drm->egl.interval)) + if (gfx_ctx_drm_wait_flip(drm->interval)) return; - waiting_for_flip = queue_flip(); + waiting_for_flip = gfx_ctx_drm_queue_flip(); if (gbm_surface_has_free_buffers(g_gbm_surface)) return; /* We have to wait for this flip to finish. * This shouldn't happen as we have triple buffered page-flips. */ - RARCH_WARN("[KMS/EGL]: Triple buffering is not working correctly ...\n"); - wait_flip(true); + RARCH_WARN("[KMS]: Triple buffering is not working correctly ...\n"); + gfx_ctx_drm_wait_flip(true); } -static bool gfx_ctx_drm_egl_set_resize(void *data, +static bool gfx_ctx_drm_set_resize(void *data, unsigned width, unsigned height) { (void)data; @@ -238,10 +285,10 @@ static bool gfx_ctx_drm_egl_set_resize(void *data, return false; } -static void gfx_ctx_drm_egl_update_window_title(void *data) +static void gfx_ctx_drm_update_window_title(void *data) { - char buf[128] = {0}; - char buf_fps[128] = {0}; + char buf[128]; + char buf_fps[128]; settings_t *settings = config_get_ptr(); video_monitor_get_fps(buf, sizeof(buf), @@ -250,20 +297,19 @@ static void gfx_ctx_drm_egl_update_window_title(void *data) runloop_msg_queue_push( buf_fps, 1, 1, false); } -static void gfx_ctx_drm_egl_get_video_size(void *data, +static void gfx_ctx_drm_get_video_size(void *data, unsigned *width, unsigned *height) { - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)data; + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; if (!drm) return; - (void)data; - *width = drm->g_fb_width; - *height = drm->g_fb_height; + *width = drm->fb_width; + *height = drm->fb_height; } -static void free_drm_resources(gfx_ctx_drm_egl_data_t *drm) +static void free_drm_resources(gfx_ctx_drm_data_t *drm) { if (!drm) return; @@ -277,22 +323,34 @@ static void free_drm_resources(gfx_ctx_drm_egl_data_t *drm) drm_free(); if (g_drm_fd >= 0) - retro_fclose(drm->g_drm); + retro_fclose(drm->drm); g_gbm_surface = NULL; g_gbm_dev = NULL; g_drm_fd = -1; } -static void gfx_ctx_drm_egl_destroy_resources(gfx_ctx_drm_egl_data_t *drm) +static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) { if (!drm) return; /* Make sure we acknowledge all page-flips. */ - wait_flip(true); + gfx_ctx_drm_wait_flip(true); - egl_destroy(drm); + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + egl_destroy(drm); +#endif + break; + case GFX_CTX_NONE: + default: + break; + } /* Restore original CRTC. */ drm_restore_crtc(); @@ -302,22 +360,22 @@ static void gfx_ctx_drm_egl_destroy_resources(gfx_ctx_drm_egl_data_t *drm) g_crtc_id = 0; g_connector_id = 0; - drm->g_fb_width = 0; - drm->g_fb_height = 0; + drm->fb_width = 0; + drm->fb_height = 0; - g_bo = NULL; - g_next_bo = NULL; + g_bo = NULL; + g_next_bo = NULL; } -static void *gfx_ctx_drm_egl_init(void *video_driver) +static void *gfx_ctx_drm_init(void *video_driver) { int fd, i; unsigned monitor_index; unsigned gpu_index = 0; const char *gpu = NULL; struct string_list *gpu_descriptors = NULL; - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*) - calloc(1, sizeof(gfx_ctx_drm_egl_data_t)); + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*) + calloc(1, sizeof(gfx_ctx_drm_data_t)); if (!drm) return NULL; @@ -331,19 +389,19 @@ nextgpu: if (!gpu_descriptors || gpu_index == gpu_descriptors->size) { - RARCH_ERR("[KMS/EGL]: Couldn't find a suitable DRM device.\n"); + RARCH_ERR("[KMS]: Couldn't find a suitable DRM device.\n"); goto error; } gpu = gpu_descriptors->elems[gpu_index++].data; - drm->g_drm = retro_fopen(gpu, RFILE_MODE_READ_WRITE, -1); - if (!drm->g_drm) + drm->drm = retro_fopen(gpu, RFILE_MODE_READ_WRITE, -1); + if (!drm->drm) { - RARCH_WARN("[KMS/EGL]: Couldn't open DRM device.\n"); + RARCH_WARN("[KMS]: Couldn't open DRM device.\n"); goto nextgpu; } - fd = retro_get_fd(drm->g_drm); + fd = retro_get_fd(drm->drm); if (!drm_get_resources(fd)) goto nextgpu; @@ -358,33 +416,33 @@ nextgpu: /* First mode is assumed to be the "optimal" * one for get_video_size() purposes. */ - drm->g_fb_width = g_drm_connector->modes[0].hdisplay; - drm->g_fb_height = g_drm_connector->modes[0].vdisplay; + drm->fb_width = g_drm_connector->modes[0].hdisplay; + drm->fb_height = g_drm_connector->modes[0].vdisplay; g_gbm_dev = gbm_create_device(fd); if (!g_gbm_dev) { - RARCH_WARN("[KMS/EGL]: Couldn't create GBM device.\n"); + RARCH_WARN("[KMS]: Couldn't create GBM device.\n"); goto nextgpu; } dir_list_free(gpu_descriptors); /* Setup the flip handler. */ - g_drm_fds.fd = fd; - g_drm_fds.events = POLLIN; - g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; - g_drm_evctx.page_flip_handler = drm_egl_flip_handler; + g_drm_fds.fd = fd; + g_drm_fds.events = POLLIN; + g_drm_evctx.version = DRM_EVENT_CONTEXT_VERSION; + g_drm_evctx.page_flip_handler = drm_flip_handler; - g_drm_fd = fd; + g_drm_fd = fd; return drm; error: dir_list_free(gpu_descriptors); - gfx_ctx_drm_egl_destroy_resources(drm); + gfx_ctx_drm_destroy_resources(drm); if (drm) free(drm); @@ -392,13 +450,15 @@ error: return NULL; } -static EGLint *egl_fill_attribs(gfx_ctx_drm_egl_data_t *drm, EGLint *attr) +static EGLint *gfx_ctx_drm_egl_fill_attribs( + gfx_ctx_drm_data_t *drm, EGLint *attr) { - switch (drm->egl.api) + switch (drm_api) { #ifdef EGL_KHR_create_context case GFX_CTX_OPENGL_API: { +#ifdef HAVE_OPENGL unsigned version = drm->egl.major * 1000 + drm->egl.minor; bool core = version >= 3001; #ifdef GL_DEBUG @@ -431,23 +491,26 @@ static EGLint *egl_fill_attribs(gfx_ctx_drm_egl_data_t *drm, EGLint *attr) *attr++ = EGL_CONTEXT_FLAGS_KHR; *attr++ = EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } - break; +#endif } #endif case GFX_CTX_OPENGL_ES_API: +#ifdef HAVE_OPENGLES *attr++ = EGL_CONTEXT_CLIENT_VERSION; - *attr++ = drm->egl.major ? (EGLint)drm->egl.major : 2; + *attr++ = drm->egl.major + ? (EGLint)drm->egl.major : 2; #ifdef EGL_KHR_create_context if (drm->egl.minor > 0) { *attr++ = EGL_CONTEXT_MINOR_VERSION_KHR; *attr++ = drm->egl.minor; } +#endif #endif break; - + case GFX_CTX_NONE: default: break; } @@ -456,6 +519,7 @@ static EGLint *egl_fill_attribs(gfx_ctx_drm_egl_data_t *drm, EGLint *attr) return attr; } +#ifdef HAVE_EGL #define DRM_EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ EGL_RED_SIZE, 1, \ @@ -464,10 +528,9 @@ static EGLint *egl_fill_attribs(gfx_ctx_drm_egl_data_t *drm, EGLint *attr) EGL_ALPHA_SIZE, 0, \ EGL_DEPTH_SIZE, 0 -static bool gfx_ctx_drm_egl_set_video_mode(void *data, - unsigned width, unsigned height, - bool fullscreen) +static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) { + const EGLint *attrib_ptr = NULL; static const EGLint egl_attribs_gl[] = { DRM_EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, @@ -488,28 +551,24 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, }; #endif +#ifdef HAVE_VG static const EGLint egl_attribs_vg[] = { DRM_EGL_ATTRIBS_BASE, EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT, EGL_NONE, }; - EGLint *egl_attribs_ptr = NULL; - const EGLint *attrib_ptr; - EGLint major, minor, n, egl_attribs[16], *attr; - float refresh_mod; - int i, ret = 0; - struct drm_fb *fb = NULL; - settings_t *settings = config_get_ptr(); - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)data; +#endif + EGLint major; + EGLint minor; + EGLint n; + EGLint egl_attribs[16]; + EGLint *egl_attribs_ptr = NULL; + EGLint *attr = NULL; - if (!drm) - return false; - - egl_install_sighandlers(); - - switch (g_egl_api) + switch (drm_api) { case GFX_CTX_OPENGL_API: +#ifdef HAVE_OPENGL attrib_ptr = egl_attribs_gl; break; case GFX_CTX_OPENGL_ES_API: @@ -519,17 +578,77 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, else #endif attrib_ptr = egl_attribs_gles; +#endif break; case GFX_CTX_OPENVG_API: +#ifdef HAVE_VG attrib_ptr = egl_attribs_vg; +#endif break; + case GFX_CTX_NONE: default: - attrib_ptr = NULL; + break; } + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + if (!egl_init_context(drm, (EGLNativeDisplayType)g_gbm_dev, &major, + &minor, &n, attrib_ptr)) + goto error; + + attr = gfx_ctx_drm_egl_fill_attribs(drm, egl_attribs); + egl_attribs_ptr = &egl_attribs[0]; + + if (!egl_create_context(drm, (attr != egl_attribs_ptr) + ? egl_attribs_ptr : NULL)) + goto error; + + if (!egl_create_surface(drm, (EGLNativeWindowType)g_gbm_surface)) + return false; +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) + glClear(GL_COLOR_BUFFER_BIT); +#endif +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + egl_swap_buffers(drm); + + return true; + +error: + egl_report_error(); + return false; +} +#endif + +static bool gfx_ctx_drm_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + float refresh_mod; + int i, ret = 0; + struct drm_fb *fb = NULL; + settings_t *settings = config_get_ptr(); + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + + if (!drm) + return false; + + drm_install_sighandler(); + /* If we use black frame insertion, - * we fake a 60 Hz monitor for 120 Hz one, etc, so try to match that. */ - refresh_mod = settings->video.black_frame_insertion ? 0.5f : 1.0f; + * we fake a 60 Hz monitor for 120 Hz one, + * etc, so try to match that. */ + refresh_mod = settings->video.black_frame_insertion + ? 0.5f : 1.0f; /* Find desired video mode, and use that. * If not fullscreen, we get desired windowed size, @@ -538,7 +657,9 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, g_drm_mode = &g_drm_connector->modes[0]; else { - /* Try to match settings->video.refresh_rate as closely as possible. + /* Try to match settings->video.refresh_rate + * as closely as possible. + * * Lower resolutions tend to have multiple supported * refresh rates as well. */ @@ -570,14 +691,14 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, goto error; } - drm->g_fb_width = g_drm_mode->hdisplay; - drm->g_fb_height = g_drm_mode->vdisplay; + drm->fb_width = g_drm_mode->hdisplay; + drm->fb_height = g_drm_mode->vdisplay; /* Create GBM surface. */ g_gbm_surface = gbm_surface_create( g_gbm_dev, - drm->g_fb_width, - drm->g_fb_height, + drm->fb_width, + drm->fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); @@ -588,33 +709,25 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, } - if (!egl_init_context(drm, (EGLNativeDisplayType)g_gbm_dev, &major, - &minor, &n, attrib_ptr)) + switch (drm_api) { - egl_report_error(); - goto error; + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + if (!gfx_ctx_drm_egl_set_video_mode(drm)) + goto error; +#endif + break; + case GFX_CTX_NONE: + default: + break; } - attr = egl_fill_attribs(drm, egl_attribs); - egl_attribs_ptr = &egl_attribs[0]; - - if (!egl_create_context(drm, (attr != egl_attribs_ptr) - ? egl_attribs_ptr : NULL)) - { - egl_report_error(); - goto error; - } - - if (!egl_create_surface(drm, (EGLNativeWindowType)g_gbm_surface)) - goto error; - - glClear(GL_COLOR_BUFFER_BIT); - egl_swap_buffers(drm); - g_bo = gbm_surface_lock_front_buffer(g_gbm_surface); - fb = drm_fb_get_from_bo(g_bo); + fb = drm_fb_get_from_bo(g_bo); - ret = drmModeSetCrtc(g_drm_fd, + ret = drmModeSetCrtc(g_drm_fd, g_crtc_id, fb->fb_id, 0, 0, &g_connector_id, 1, g_drm_mode); if (ret < 0) goto error; @@ -622,7 +735,7 @@ static bool gfx_ctx_drm_egl_set_video_mode(void *data, return true; error: - gfx_ctx_drm_egl_destroy_resources(drm); + gfx_ctx_drm_destroy_resources(drm); if (drm) free(drm); @@ -631,18 +744,18 @@ error: } -static void gfx_ctx_drm_egl_destroy(void *data) +static void gfx_ctx_drm_destroy(void *data) { - gfx_ctx_drm_egl_data_t *drm = (gfx_ctx_drm_egl_data_t*)data; + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; if (!drm) return; - gfx_ctx_drm_egl_destroy_resources(drm); + gfx_ctx_drm_destroy_resources(drm); free(drm); } -static void gfx_ctx_drm_egl_input_driver(void *data, +static void gfx_ctx_drm_input_driver(void *data, const input_driver_t **input, void **input_data) { (void)data; @@ -650,49 +763,64 @@ static void gfx_ctx_drm_egl_input_driver(void *data, *input_data = NULL; } -static bool gfx_ctx_drm_egl_has_focus(void *data) +static bool gfx_ctx_drm_has_focus(void *data) { return true; } -static bool gfx_ctx_drm_egl_suppress_screensaver(void *data, bool enable) +static bool gfx_ctx_drm_suppress_screensaver(void *data, bool enable) { (void)data; (void)enable; return false; } -static bool gfx_ctx_drm_egl_has_windowed(void *data) +static bool gfx_ctx_drm_has_windowed(void *data) { (void)data; return false; } -static bool gfx_ctx_drm_egl_bind_api(void *video_driver, +static bool gfx_ctx_drm_bind_api(void *video_driver, enum gfx_ctx_api api, unsigned major, unsigned minor) { (void)video_driver; +#ifdef HAVE_EGL g_egl_major = major; g_egl_minor = minor; - g_egl_api = api; +#endif + drm_api = api; switch (api) { case GFX_CTX_OPENGL_API: +#if defined(HAVE_EGL) && defined(HAVE_OPENGL) + #ifndef EGL_KHR_create_context if ((major * 1000 + minor) >= 3001) return false; #endif return eglBindAPI(EGL_OPENGL_API); +#else + break; +#endif case GFX_CTX_OPENGL_ES_API: +#if defined(HAVE_EGL) && defined(HAVE_OPENGLES) + #ifndef EGL_KHR_create_context if (major >= 3) return false; #endif return eglBindAPI(EGL_OPENGL_ES_API); +#else + break; +#endif case GFX_CTX_OPENVG_API: +#if defined(HAVE_EGL) && defined(HAVE_VG) return eglBindAPI(EGL_OPENVG_API); +#endif + case GFX_CTX_NONE: default: break; } @@ -700,31 +828,67 @@ static bool gfx_ctx_drm_egl_bind_api(void *video_driver, return false; } +static gfx_ctx_proc_t gfx_ctx_drm_get_proc_address(const char *symbol) +{ + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + return egl_get_proc_address(symbol); +#else + break; +#endif + case GFX_CTX_NONE: + default: + break; + } -const gfx_ctx_driver_t gfx_ctx_drm_egl = { - gfx_ctx_drm_egl_init, - gfx_ctx_drm_egl_destroy, - gfx_ctx_drm_egl_bind_api, - gfx_ctx_drm_egl_swap_interval, - gfx_ctx_drm_egl_set_video_mode, - gfx_ctx_drm_egl_get_video_size, + return NULL; +} + +static void gfx_ctx_drm_bind_hw_render(void *data, bool enable) +{ + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + egl_bind_hw_render(data, enable); +#endif + break; + case GFX_CTX_NONE: + default: + break; + } +} + +const gfx_ctx_driver_t gfx_ctx_drm = { + gfx_ctx_drm_init, + gfx_ctx_drm_destroy, + gfx_ctx_drm_bind_api, + gfx_ctx_drm_swap_interval, + gfx_ctx_drm_set_video_mode, + gfx_ctx_drm_get_video_size, NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ NULL, /* get_metrics */ NULL, - gfx_ctx_drm_egl_update_window_title, - gfx_ctx_drm_egl_check_window, - gfx_ctx_drm_egl_set_resize, - gfx_ctx_drm_egl_has_focus, - gfx_ctx_drm_egl_suppress_screensaver, - gfx_ctx_drm_egl_has_windowed, - gfx_ctx_drm_egl_swap_buffers, - gfx_ctx_drm_egl_input_driver, - egl_get_proc_address, + gfx_ctx_drm_update_window_title, + gfx_ctx_drm_check_window, + gfx_ctx_drm_set_resize, + gfx_ctx_drm_has_focus, + gfx_ctx_drm_suppress_screensaver, + gfx_ctx_drm_has_windowed, + gfx_ctx_drm_swap_buffers, + gfx_ctx_drm_input_driver, + gfx_ctx_drm_get_proc_address, NULL, NULL, NULL, - "kms-egl", - egl_bind_hw_render, + "kms", + gfx_ctx_drm_bind_hw_render, }; diff --git a/gfx/drivers_context/sdl_gl_ctx.c b/gfx/drivers_context/sdl_gl_ctx.c index c0f2b8960b..e5984d8af5 100644 --- a/gfx/drivers_context/sdl_gl_ctx.c +++ b/gfx/drivers_context/sdl_gl_ctx.c @@ -20,7 +20,7 @@ #include "../../runloop.h" #include "../common/gl_common.h" -static enum gfx_ctx_api g_api = GFX_CTX_OPENGL_API; +static enum gfx_ctx_api sdl_api = GFX_CTX_OPENGL_API; static unsigned g_major = 2; static unsigned g_minor = 1; @@ -132,7 +132,7 @@ static bool sdl_ctx_bind_api(void *data, enum gfx_ctx_api api, unsigned major, SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); #endif - g_api = api; + sdl_api = api; g_major = major; g_minor = minor; diff --git a/gfx/drivers_context/vc_egl_ctx.c b/gfx/drivers_context/vc_egl_ctx.c index 19798ce492..ced37c1d2d 100644 --- a/gfx/drivers_context/vc_egl_ctx.c +++ b/gfx/drivers_context/vc_egl_ctx.c @@ -51,6 +51,7 @@ typedef struct { unsigned res; } vc_ctx_data_t; +static enum gfx_ctx_api vc_api; static PFNEGLCREATEIMAGEKHRPROC peglCreateImageKHR; static PFNEGLDESTROYIMAGEKHRPROC peglDestroyImageKHR; @@ -186,7 +187,7 @@ static void *gfx_ctx_vc_init(void *video_driver) goto error; } - if (!egl_create_context(vc, (g_egl_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL)) + if (!egl_create_context(vc, (vc_api == GFX_CTX_OPENGL_ES_API) ? context_attributes : NULL)) { egl_report_error(); goto error; @@ -303,7 +304,7 @@ static bool gfx_ctx_vc_bind_api(void *data, (void)major; (void)minor; - g_egl_api = api; + vc_api = api; switch (api) { @@ -354,7 +355,7 @@ static void gfx_ctx_vc_destroy(void *data) if (vc->egl.ctx) { - gfx_ctx_vc_bind_api(data, vc->egl.api, 0, 0); + gfx_ctx_vc_bind_api(data, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(vc->egl.dpy, vc->egl.ctx); @@ -373,7 +374,7 @@ static void gfx_ctx_vc_destroy(void *data) if (vc->egl.surf) { - gfx_ctx_vc_bind_api(data, g_egl_api, 0, 0); + gfx_ctx_vc_bind_api(data, vc_api, 0, 0); eglDestroySurface(vc->egl.dpy, vc->egl.surf); } @@ -386,7 +387,7 @@ static void gfx_ctx_vc_destroy(void *data) eglBindAPI(EGL_OPENVG_API); eglMakeCurrent(vc->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - gfx_ctx_vc_bind_api(data, vc->egl.api, 0, 0); + gfx_ctx_vc_bind_api(data, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(vc->egl.dpy); @@ -459,7 +460,7 @@ static bool gfx_ctx_vc_image_buffer_init(void *data, }; /* Don't bother, we just use VGImages for our EGLImage anyway. */ - if (vc->egl.api == GFX_CTX_OPENVG_API) + if (vc_api == GFX_CTX_OPENVG_API) return false; peglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) @@ -496,7 +497,7 @@ static bool gfx_ctx_vc_image_buffer_init(void *data, goto fail; } - gfx_ctx_vc_bind_api(NULL, vc->egl.api, 0, 0); + gfx_ctx_vc_bind_api(NULL, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, vc->egl.surf, vc->egl.surf, vc->egl.ctx); vc->smooth = video->smooth; @@ -515,7 +516,7 @@ fail: vc->pbuff_surf = EGL_NO_CONTEXT; } - gfx_ctx_vc_bind_api(NULL, g_egl_api, 0, 0); + gfx_ctx_vc_bind_api(NULL, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, vc->egl.surf, vc->egl.surf, vc->egl.ctx); return false; @@ -559,7 +560,7 @@ static bool gfx_ctx_vc_image_buffer_write(void *data, const void *frame, unsigne height); *image_handle = vc->eglBuffer[index]; - gfx_ctx_vc_bind_api(NULL, vc->egl.api, 0, 0); + gfx_ctx_vc_bind_api(NULL, vc_api, 0, 0); eglMakeCurrent(vc->egl.dpy, vc->egl.surf, vc->egl.surf, vc->egl.ctx); return ret; diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 0b36c192b1..7b8954db18 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -43,7 +43,7 @@ #include "../common/gl_common.h" #endif -static volatile sig_atomic_t g_quit = 0; +static volatile sig_atomic_t wl_quit = 0; typedef struct gfx_ctx_wayland_data { @@ -55,6 +55,8 @@ typedef struct gfx_ctx_wayland_data int fd; unsigned width; unsigned height; + unsigned physical_width; + unsigned physical_height; struct wl_display *dpy; struct wl_registry *registry; struct wl_compositor *compositor; @@ -78,18 +80,18 @@ static enum gfx_ctx_api wl_api; #define EGL_OPENGL_ES3_BIT_KHR 0x0040 #endif -static void sighandler(int sig) +static void wl_sighandler(int sig) { (void)sig; - g_quit = 1; + wl_quit = 1; } -static void install_sighandlers(void) +static void wl_install_sighandler(void) { struct sigaction sa; sa.sa_sigaction = NULL; - sa.sa_handler = sighandler; + sa.sa_handler = wl_sighandler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); @@ -117,7 +119,7 @@ static void shell_surface_handle_configure(void *data, wl->width = wl->buffer_scale * width; wl->height = wl->buffer_scale * height; - RARCH_LOG("[Wayland/EGL]: Surface configure: %u x %u.\n", + RARCH_LOG("[Wayland]: Surface configure: %u x %u.\n", wl->width, wl->height); } @@ -134,17 +136,92 @@ static const struct wl_shell_surface_listener shell_surface_listener = { shell_surface_handle_popup_done, }; +static void display_handle_geometry(void *data, + struct wl_output *output, + int x, int y, + int physical_width, int physical_height, + int subpixel, + const char *make, + const char *model, + int transform) +{ + (void)data; + (void)output; + (void)x; + (void)y; + (void)subpixel; + (void)make; + (void)model; + (void)transform; + + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + wl->physical_width = physical_width; + wl->physical_height = physical_height; + RARCH_LOG("[Wayland]: Physical width: %d mm x %d mm.\n", + physical_width, physical_height); +} + +static void display_handle_mode(void *data, + struct wl_output *output, + uint32_t flags, + int width, + int height, + int refresh) +{ + (void)output; + (void)flags; + + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + wl->width = width; + wl->height = height; + + RARCH_LOG("[Wayland]: Video mode: %d x %d @ %d Hz.\n", + width, height, refresh); +} + +static void display_handle_done(void *data, + struct wl_output *output) +{ + (void)data; + (void)output; +} + +static void display_handle_scale(void *data, + struct wl_output *output, + int32_t factor) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + + RARCH_LOG("[Wayland]: Setting buffer scale factor to %d.\n", factor); + wl->buffer_scale = factor; +} + +static const struct wl_output_listener output_listener = { + display_handle_geometry, + display_handle_mode, + display_handle_done, + display_handle_scale, +}; + /* Registry callbacks. */ static void registry_handle_global(void *data, struct wl_registry *reg, uint32_t id, const char *interface, uint32_t version) { gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + struct wl_output *output; (void)version; if (string_is_equal(interface, "wl_compositor")) wl->compositor = (struct wl_compositor*)wl_registry_bind(reg, id, &wl_compositor_interface, 3); + else if (string_is_equal(interface, "wl_output")) + { + output = (struct wl_output*)wl_registry_bind(reg, + id, &wl_output_interface, 2); + wl_output_add_listener(output, &output_listener, wl); + wl_display_roundtrip(wl->dpy); + } else if (string_is_equal(interface, "wl_shell")) wl->shell = (struct wl_shell*) wl_registry_bind(reg, id, &wl_shell_interface, 1); @@ -242,7 +319,7 @@ static void flush_wayland_fd(gfx_ctx_wayland_data_t *wl) if (fd.revents & (POLLERR | POLLHUP)) { close(wl->fd); - g_quit = true; + wl_quit = true; } if (fd.revents & POLLIN) @@ -289,7 +366,7 @@ static void gfx_ctx_wl_check_window(void *data, bool *quit, *height = new_height; } - *quit = g_quit; + *quit = wl_quit; } static bool gfx_ctx_wl_set_resize(void *data, unsigned width, unsigned height) @@ -353,6 +430,35 @@ static void gfx_ctx_wl_get_video_size(void *data, *height = wl->height; } +static bool gfx_ctx_wl_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + if (wl->physical_width == 0 || wl->physical_height == 0) + return false; + + switch (type) + { + case DISPLAY_METRIC_MM_WIDTH: + *value = (float)wl->physical_width; + break; + + case DISPLAY_METRIC_MM_HEIGHT: + *value = (float)wl->physical_height; + break; + + case DISPLAY_METRIC_DPI: + *value = (float)wl->width * 25.4f / (float)wl->physical_width; + break; + + default: + *value = 0.0f; + return false; + } + + return true; +} + #define DEFAULT_WINDOWED_WIDTH 640 #define DEFAULT_WINDOWED_HEIGHT 480 @@ -368,7 +474,6 @@ static void gfx_ctx_wl_get_video_size(void *data, static void *gfx_ctx_wl_init(void *video_driver) { - #ifdef HAVE_OPENGL static const EGLint egl_attribs_gl[] = { WL_EGL_ATTRIBS_BASE, @@ -418,7 +523,7 @@ static void *gfx_ctx_wl_init(void *video_driver) (void)video_driver; #ifdef HAVE_EGL - switch (wl->egl.api) + switch (wl_api) { case GFX_CTX_OPENGL_API: #ifdef HAVE_OPENGL @@ -448,34 +553,21 @@ static void *gfx_ctx_wl_init(void *video_driver) } #endif - g_quit = 0; + wl_quit = 0; wl->dpy = wl_display_connect(NULL); + wl->buffer_scale = 1; + if (!wl->dpy) { RARCH_ERR("Failed to connect to Wayland server.\n"); goto error; } - install_sighandlers(); + wl_install_sighandler(); wl->registry = wl_display_get_registry(wl->dpy); wl_registry_add_listener(wl->registry, ®istry_listener, wl); - - switch (wl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - case GFX_CTX_OPENVG_API: -#ifdef HAVE_EGL - wl_display_dispatch(wl->dpy); -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - wl_display_roundtrip(wl->dpy); if (!wl->compositor) @@ -534,7 +626,7 @@ error: #ifdef HAVE_EGL static EGLint *egl_fill_attribs(gfx_ctx_wayland_data_t *wl, EGLint *attr) { - switch (wl->egl.api) + switch (wl_api) { #ifdef EGL_KHR_create_context case GFX_CTX_OPENGL_API: @@ -668,10 +760,8 @@ static bool gfx_ctx_wl_set_video_mode(void *data, wl->width = width ? width : DEFAULT_WINDOWED_WIDTH; wl->height = height ? height : DEFAULT_WINDOWED_HEIGHT; - /* TODO: Use wl_output::scale to obtain correct value. */ - wl->buffer_scale = 1; - wl->surface = wl_compositor_create_surface(wl->compositor); + wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale); switch (wl_api) { @@ -784,7 +874,6 @@ static bool gfx_ctx_wl_bind_api(void *video_driver, #ifdef HAVE_EGL g_egl_major = major; g_egl_minor = minor; - g_egl_api = api; #endif switch (api) @@ -1056,7 +1145,7 @@ const gfx_ctx_driver_t gfx_ctx_wayland = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - NULL, /* get_metrics */ + gfx_ctx_wl_get_metrics, NULL, gfx_ctx_wl_update_window_title, gfx_ctx_wl_check_window, diff --git a/gfx/drivers_context/x_ctx.c b/gfx/drivers_context/x_ctx.c index cdec979196..141dea6bd3 100644 --- a/gfx/drivers_context/x_ctx.c +++ b/gfx/drivers_context/x_ctx.c @@ -61,7 +61,7 @@ typedef struct gfx_ctx_x_data static unsigned g_major; static unsigned g_minor; -static enum gfx_ctx_api g_api; +static enum gfx_ctx_api x_api; #ifdef HAVE_OPENGL static PFNGLXCREATECONTEXTATTRIBSARBPROC glx_create_context_attribs; @@ -83,7 +83,7 @@ static void gfx_ctx_x_destroy_resources(gfx_ctx_x_data_t *x) if (g_x11_dpy) { - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -164,7 +164,7 @@ static void gfx_ctx_x_destroy(void *data) gfx_ctx_x_destroy_resources(x); - switch (g_api) + switch (x_api) { case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN @@ -184,7 +184,7 @@ static void gfx_ctx_x_swap_interval(void *data, unsigned interval) { gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data; - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -232,7 +232,7 @@ static void gfx_ctx_x_swap_buffers(void *data) { gfx_ctx_x_data_t *x = (gfx_ctx_x_data_t*)data; - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -264,7 +264,7 @@ static void gfx_ctx_x_check_window(void *data, bool *quit, x11_check_window(data, quit, resize, width, height, frame_count); - switch (g_api) + switch (x_api) { case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN @@ -289,7 +289,7 @@ static bool gfx_ctx_x_set_resize(void *data, (void)width; (void)height; - switch (g_api) + switch (x_api) { case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN @@ -346,7 +346,7 @@ static void *gfx_ctx_x_init(void *data) goto error; - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -440,7 +440,7 @@ static bool gfx_ctx_x_set_video_mode(void *data, windowed_full = settings->video.windowed_fullscreen; true_full = false; - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -516,7 +516,7 @@ static bool gfx_ctx_x_set_video_mode(void *data, (true_full ? CWOverrideRedirect : 0), &swa); XSetWindowBackground(g_x11_dpy, g_x11_win, 0); - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -568,7 +568,7 @@ static bool gfx_ctx_x_set_video_mode(void *data, x11_event_queue_check(&event); - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -678,7 +678,7 @@ static bool gfx_ctx_x_set_video_mode(void *data, x11_install_quit_atom(); - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -777,7 +777,7 @@ static bool gfx_ctx_x_has_windowed(void *data) static gfx_ctx_proc_t gfx_ctx_x_get_proc_address(const char *symbol) { - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: @@ -806,7 +806,7 @@ static bool gfx_ctx_x_bind_api(void *data, enum gfx_ctx_api api, { case GFX_CTX_OPENGL_API: #ifdef HAVE_OPENGL - g_api = GFX_CTX_OPENGL_API; + x_api = GFX_CTX_OPENGL_API; return true; #else break; @@ -824,7 +824,7 @@ static bool gfx_ctx_x_bind_api(void *data, enum gfx_ctx_api api, g_major = 2; /* ES 2.0. */ g_minor = 0; } - g_api = GFX_CTX_OPENGL_ES_API; + x_api = GFX_CTX_OPENGL_ES_API; return ret; } #else @@ -832,7 +832,7 @@ static bool gfx_ctx_x_bind_api(void *data, enum gfx_ctx_api api, #endif case GFX_CTX_VULKAN_API: #ifdef HAVE_VULKAN - g_api = api; + x_api = api; return true; #else break; @@ -857,7 +857,7 @@ static void gfx_ctx_x_bind_hw_render(void *data, bool enable) if (!x) return; - switch (g_api) + switch (x_api) { case GFX_CTX_OPENGL_API: case GFX_CTX_OPENGL_ES_API: diff --git a/gfx/drivers_context/xegl_ctx.c b/gfx/drivers_context/xegl_ctx.c index 9a7f9868f8..4094720e87 100644 --- a/gfx/drivers_context/xegl_ctx.c +++ b/gfx/drivers_context/xegl_ctx.c @@ -33,7 +33,9 @@ typedef struct { bool should_reset_mode; } xegl_ctx_data_t; -static int egl_nul_handler(Display *dpy, XErrorEvent *event) +static enum gfx_ctx_api x_api; + +static int x_nul_handler(Display *dpy, XErrorEvent *event) { (void)dpy; (void)event; @@ -130,7 +132,7 @@ static void *gfx_ctx_xegl_init(void *video_driver) if (!xegl) return NULL; - switch (xegl->egl.api) + switch (x_api) { case GFX_CTX_OPENGL_API: attrib_ptr = egl_attribs_gl; @@ -172,7 +174,7 @@ error: static EGLint *xegl_fill_attribs(xegl_ctx_data_t *xegl, EGLint *attr) { - switch (xegl->egl.api) + switch (x_api) { #ifdef EGL_KHR_create_context case GFX_CTX_OPENGL_API: @@ -378,7 +380,7 @@ static bool gfx_ctx_xegl_set_video_mode(void *data, /* This can blow up on some drivers. It's not fatal, * so override errors for this call. */ - old_handler = XSetErrorHandler(egl_nul_handler); + old_handler = XSetErrorHandler(x_nul_handler); XSetInputFocus(g_x11_dpy, g_x11_win, RevertToNone, CurrentTime); XSync(g_x11_dpy, False); XSetErrorHandler(old_handler); @@ -445,7 +447,7 @@ static bool gfx_ctx_xegl_bind_api(void *video_driver, { g_egl_major = major; g_egl_minor = minor; - g_egl_api = api; + x_api = api; switch (api) { diff --git a/gfx/drivers_font/vulkan_raster_font.c b/gfx/drivers_font/vulkan_raster_font.c index 5cd0585b62..465c94e8d6 100644 --- a/gfx/drivers_font/vulkan_raster_font.c +++ b/gfx/drivers_font/vulkan_raster_font.c @@ -36,12 +36,14 @@ static void *vulkan_raster_font_init_font(void *data, const struct font_atlas *atlas = NULL; vulkan_raster_t *font = (vulkan_raster_t*)calloc(1, sizeof(*font)); +#if 0 VkComponentMapping swizzle = { VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_R, }; +#endif if (!font) return NULL; @@ -58,7 +60,8 @@ static void *vulkan_raster_font_init_font(void *data, atlas = font->font_driver->get_atlas(font->font_data); font->texture = vulkan_create_texture(font->vk, NULL, - atlas->width, atlas->height, VK_FORMAT_R8_UNORM, atlas->buffer, &swizzle, VULKAN_TEXTURE_STATIC); + atlas->width, atlas->height, VK_FORMAT_R8_UNORM, atlas->buffer, + NULL /*&swizzle*/, VULKAN_TEXTURE_STATIC); return font; } @@ -224,7 +227,7 @@ static void vulkan_raster_font_setup_viewport(vulkan_raster_t *font, bool full_s static void vulkan_raster_font_flush(vulkan_raster_t *font) { const struct vk_draw_triangles call = { - font->vk->pipelines.alpha_blend, + font->vk->pipelines.font, &font->texture, font->vk->samplers.nearest, &font->vk->mvp, diff --git a/gfx/video_context_driver.c b/gfx/video_context_driver.c index 687c58d106..e73b3dc169 100644 --- a/gfx/video_context_driver.c +++ b/gfx/video_context_driver.c @@ -58,7 +58,7 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { &gfx_ctx_x_egl, #endif #if defined(HAVE_KMS) - &gfx_ctx_drm_egl, + &gfx_ctx_drm, #endif #if defined(ANDROID) &gfx_ctx_android, diff --git a/gfx/video_context_driver.h b/gfx/video_context_driver.h index ab5d414caf..0c2fcc8ca1 100644 --- a/gfx/video_context_driver.h +++ b/gfx/video_context_driver.h @@ -252,7 +252,7 @@ extern const gfx_ctx_driver_t gfx_ctx_x_egl; extern const gfx_ctx_driver_t gfx_ctx_wayland; extern const gfx_ctx_driver_t gfx_ctx_x; extern const gfx_ctx_driver_t gfx_ctx_d3d; -extern const gfx_ctx_driver_t gfx_ctx_drm_egl; +extern const gfx_ctx_driver_t gfx_ctx_drm; extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev; extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev; extern const gfx_ctx_driver_t gfx_ctx_android; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index dca890a87e..d7fe0fc0b5 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -242,14 +242,11 @@ const char* config_get_video_driver_options(void) return char_list_new_special(STRING_LIST_VIDEO_DRIVERS, NULL); } -#ifdef HAVE_VULKAN static bool hw_render_context_is_vulkan(enum retro_hw_context_type type) { return type == RETRO_HW_CONTEXT_VULKAN; } -#endif -#if defined(HAVE_OPENGL) && defined(HAVE_FBO) static bool hw_render_context_is_gl(enum retro_hw_context_type type) { switch (type) @@ -266,7 +263,6 @@ static bool hw_render_context_is_gl(enum retro_hw_context_type type) return false; } -#endif static bool find_video_driver(void) { @@ -276,27 +272,27 @@ static bool find_video_driver(void) if (video_driver_ctl(RARCH_DISPLAY_CTL_IS_HW_CONTEXT, NULL)) { - current_video = NULL; struct retro_hw_render_callback *hwr = video_driver_callback(); + current_video = NULL; (void)hwr; -#if defined(HAVE_VULKAN) if (hwr && hw_render_context_is_vulkan(hwr->context_type)) { +#if defined(HAVE_VULKAN) RARCH_LOG("Using HW render, Vulkan driver forced.\n"); current_video = &video_vulkan; - } #endif + } -#if defined(HAVE_OPENGL) && defined(HAVE_FBO) if (hwr && hw_render_context_is_gl(hwr->context_type)) { +#if defined(HAVE_OPENGL) && defined(HAVE_FBO) RARCH_LOG("Using HW render, OpenGL driver forced.\n"); current_video = &video_gl; - } #endif + } if (current_video) return true; diff --git a/griffin/griffin.c b/griffin/griffin.c index 9b1393d0d4..a05cfdeceb 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -141,19 +141,17 @@ VIDEO CONTEXT #include "../gfx/common/vulkan_common.c" #endif -#if defined(HAVE_OPENGL) - #if defined(HAVE_KMS) -#include "../gfx/drivers_context/drm_egl_ctx.c" -#endif -#if defined(HAVE_VIDEOCORE) -#include "../gfx/drivers_context/vc_egl_ctx.c" -#endif - +#include "../gfx/drivers_context/drm_ctx.c" #endif #if defined(HAVE_EGL) #include "../gfx/common/egl_common.c" + +#if defined(HAVE_VIDEOCORE) +#include "../gfx/drivers_context/vc_egl_ctx.c" +#endif + #endif #if defined(HAVE_X11) diff --git a/input/input_remapping.c b/input/input_remapping.c index a87917fbe1..61f800ae5b 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -39,8 +39,8 @@ bool input_remapping_load_file(void *data, const char *path) if (!conf || string_is_empty(path)) return false; - strlcpy(settings->input.remapping_path, path, - sizeof(settings->input.remapping_path)); + strlcpy(global->name.remapfile, path, + sizeof(global->name.remapfile)); for (i = 0; i < MAX_USERS; i++) { diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index 9a097cc4a3..a17c61fd20 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -68,12 +68,12 @@ static void menu_action_setting_disp_set_label_remap_file_load( const char *path, char *s2, size_t len2) { - settings_t *settings = config_get_ptr(); + global_t *global = global_get_ptr(); *w = 19; strlcpy(s2, path, len2); - if (settings) - fill_pathname_base(s, settings->input.remapping_path, + if (global) + fill_pathname_base(s, global->name.remapfile, len); } @@ -379,13 +379,17 @@ static void menu_action_setting_disp_set_label_input_desc( const char *path, char *s2, size_t len2) { - settings_t *settings = config_get_ptr(); - unsigned inp_desc_index_offset = type - MENU_SETTINGS_INPUT_DESC_BEGIN; - unsigned inp_desc_user = inp_desc_index_offset / + char descriptor[PATH_MAX_LENGTH]; + const struct retro_keybind *auto_bind = NULL; + const struct retro_keybind *keybind = NULL; + settings_t *settings = config_get_ptr(); + unsigned inp_desc_index_offset = + type - MENU_SETTINGS_INPUT_DESC_BEGIN; + unsigned inp_desc_user = inp_desc_index_offset / (RARCH_FIRST_CUSTOM_BIND + 4); unsigned inp_desc_button_index_offset = inp_desc_index_offset - (inp_desc_user * (RARCH_FIRST_CUSTOM_BIND + 4)); - unsigned remap_id = 0; + unsigned remap_id = 0; if (!settings) return; @@ -393,14 +397,11 @@ static void menu_action_setting_disp_set_label_input_desc( remap_id = settings->input.remap_ids [inp_desc_user][inp_desc_button_index_offset]; - const struct retro_keybind *keybind = - (const struct retro_keybind*) + keybind = (const struct retro_keybind*) &settings->input.binds[inp_desc_user][remap_id]; - const struct retro_keybind *auto_bind = - (const struct retro_keybind*) + auto_bind = (const struct retro_keybind*) input_get_auto_bind(inp_desc_user, remap_id); - char descriptor[PATH_MAX_LENGTH]; input_config_get_bind_string(descriptor, keybind, auto_bind, sizeof(descriptor)); diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index 26f9dd6aac..38783fc43e 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -42,12 +42,12 @@ static int action_start_remap_file_load(unsigned type, const char *label) { - settings_t *settings = config_get_ptr(); + global_t *global = global_get_ptr(); - if (!settings) + if (!global) return -1; - settings->input.remapping_path[0] = '\0'; + global->name.remapfile[0] = '\0'; input_remapping_set_defaults(); return 0; } diff --git a/menu/drivers/menu_generic.c b/menu/drivers/menu_generic.c index ef1cd72963..388b685687 100644 --- a/menu/drivers/menu_generic.c +++ b/menu/drivers/menu_generic.c @@ -336,11 +336,11 @@ int generic_menu_iterate(void *data, void *userdata, enum menu_action action) BIT64_SET(menu->state, MENU_STATE_POP_STACK); break; case ITERATE_TYPE_DEFAULT: - /* FIXME: Crappy hack, needed for mouse controls to not be completely broken - * in case we press back. + /* FIXME: Crappy hack, needed for mouse controls + * to not be completely broken in case we press back. * - * We need to fix this entire mess, mouse controls should not rely on a - * hack like this in order to work. */ + * We need to fix this entire mess, mouse controls + * should not rely on a hack like this in order to work. */ selection = max(min(selection, (menu_entries_get_size() - 1)), 0); menu_entry_get(&entry, 0, selection, NULL, false); diff --git a/menu/drivers/xui.cpp b/menu/drivers/xui.cpp index 7d0df46f72..2662999f5a 100644 --- a/menu/drivers/xui.cpp +++ b/menu/drivers/xui.cpp @@ -243,13 +243,13 @@ HRESULT XuiTextureLoader(IXuiDevice *pDevice, LPCWSTR szFileName, if(hr != D3DXERR_INVALIDDATA ) { - pImageInfo->Depth = pSrc.Depth; - pImageInfo->Format = pSrc.Format; - pImageInfo->Height = pSrc.Height; + pImageInfo->Depth = pSrc.Depth; + pImageInfo->Format = pSrc.Format; + pImageInfo->Height = pSrc.Height; pImageInfo->ImageFileFormat = pSrc.ImageFileFormat; - pImageInfo->MipLevels = pSrc.MipLevels; - pImageInfo->ResourceType = pSrc.ResourceType; - pImageInfo->Width = pSrc.Width; + pImageInfo->MipLevels = pSrc.MipLevels; + pImageInfo->ResourceType = pSrc.ResourceType; + pImageInfo->Width = pSrc.Width; } else RARCH_ERR("D3DXERR_INVALIDDATA Encountered\n"); @@ -293,7 +293,8 @@ static void* xui_init(void **userdata) 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)) { @@ -387,8 +388,8 @@ static void xui_render_message(const char *msg) float msg_height = 120; float msg_offset = 32; - font_parms.x = msg_width; - font_parms.y = msg_height + (msg_offset * j); + font_parms.x = msg_width; + font_parms.y = msg_height + (msg_offset * j); font_parms.scale = 21; video_driver_set_osd_msg(msg, &font_parms, NULL); @@ -404,7 +405,7 @@ static void xui_frame(void *data) XUIMessageRender msgRender; D3DXMATRIX matOrigView; LPDIRECT3DDEVICE d3dr; - const char *message; + const char *message = NULL; D3DVIEWPORT vp_full = {0}; 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 ); - XuiMessageRender( &msg, &msgRender, app.GetDC(), 0xffffffff, XUI_BLEND_NORMAL ); + XuiMessageRender( &msg, &msgRender, + app.GetDC(), 0xffffffff, XUI_BLEND_NORMAL ); XuiSendMessage( app.GetRootObj(), &msg ); 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) { - bool libretro_running = menu_display_ctl(MENU_DISPLAY_CTL_LIBRETRO_RUNNING, NULL); - - if (libretro_running) + if (menu_display_ctl(MENU_DISPLAY_CTL_LIBRETRO_RUNNING, NULL)) XuiElementSetShow(m_background, FALSE); else 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) { - 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) { 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) diff --git a/menu/drivers/zarch.c b/menu/drivers/zarch.c index 0a102916c1..f88181d269 100644 --- a/menu/drivers/zarch.c +++ b/menu/drivers/zarch.c @@ -213,8 +213,10 @@ static void zarch_zui_font(void) menu_display_ctl(MENU_DISPLAY_CTL_FONT_SIZE, &font_size); - fill_pathname_join(mediapath, settings->assets_directory, "zarch", sizeof(mediapath)); - fill_pathname_join(fontpath, mediapath, "Roboto-Condensed.ttf", sizeof(fontpath)); + fill_pathname_join(mediapath, + settings->assets_directory, "zarch", sizeof(mediapath)); + fill_pathname_join(fontpath, + mediapath, "Roboto-Condensed.ttf", sizeof(fontpath)); font_info.path = fontpath; 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: return menu_input_pointer_state(MENU_POINTER_Y_AXIS); 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; if (zui->action == MENU_ACTION_OK) return 1; @@ -260,7 +263,8 @@ static int16_t zarch_zui_input_state(zui_t *zui, enum zarch_zui_input_state stat 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 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) 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; 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; } -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 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) 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) result = true; @@ -314,7 +321,8 @@ static unsigned zarch_zui_hash(zui_t *zui, const char *s) 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; @@ -375,19 +383,21 @@ static float zarch_zui_randf(float min, float max) 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; } #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 bool initialized = false; static int timeout = 0; - unsigned i, max_gen = 2; + unsigned i, max_gen = 2; if (!initialized) { @@ -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); p->y += p->yspeed; - p->x += zarch_zui_scalef(mouse_x, 0, width, -0.3, 0.3) + p->xspeed; - - p->alive = p->y >= 0 && p->y < height && p->x >= 0 && p->x < width; - + 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; } 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; } - 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++; } } -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); 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) { - 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, @@ -506,7 +519,8 @@ static bool zarch_zui_list_item(zui_t *zui, zui_tabbed_t *tab, int x1, int y1, } 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; } @@ -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; } -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; 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; } -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) 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_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); zui->load_dlist_first = 0; } 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); 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) && - 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); } @@ -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) { - 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] != '.') break; 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) 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) { @@ -747,7 +771,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed) if (path_is_directory(path)) 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)) { 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_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); @@ -781,7 +807,8 @@ static int zarch_zui_render_lay_root_load(zui_t *zui, zui_tabbed_t *tabbed) 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)) { @@ -791,7 +818,8 @@ static int zarch_zui_render_lay_root_collections(zui_t *zui, zui_tabbed_t *tabbe 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)) { @@ -855,7 +883,8 @@ static int zarch_zui_render_lay_root(zui_t *zui) else 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; } @@ -923,7 +952,8 @@ static int zarch_zui_render_pick_core(zui_t *zui) 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; return 1; } @@ -999,7 +1029,8 @@ static void zarch_frame(void *data) 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); switch (layout) @@ -1078,7 +1109,8 @@ static void *zarch_init(void **userdata) int unused; zui_t *zui = NULL; 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) goto error; @@ -1112,7 +1144,8 @@ static void *zarch_init(void **userdata) if (!string_is_empty(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; @@ -1276,18 +1309,22 @@ static bool zarch_menu_init_list(void *data) 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 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_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 event_cmd_ctl(EVENT_CMD_HISTORY_INIT, NULL); diff --git a/menu/drivers_display/menu_display_d3d.cpp b/menu/drivers_display/menu_display_d3d.cpp index 37ecb13f02..e4d06ad19d 100644 --- a/menu/drivers_display/menu_display_d3d.cpp +++ b/menu/drivers_display/menu_display_d3d.cpp @@ -126,11 +126,12 @@ static void menu_display_d3d_draw(void *data) draw->height = 1; 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) - draw->coords->vertex = &d3d_vertexes[0]; + draw->coords->vertex = &d3d_vertexes[0]; if (!draw->coords->tex_coord) - draw->coords->tex_coord = &d3d_tex_coords[0]; + draw->coords->tex_coord = &d3d_tex_coords[0]; if (!draw->coords->lut_tex_coord) draw->coords->lut_tex_coord = &d3d_tex_coords[0]; diff --git a/menu/drivers_display/menu_display_vulkan.c b/menu/drivers_display/menu_display_vulkan.c index 34ac46a2db..41406ddbb2 100644 --- a/menu/drivers_display/menu_display_vulkan.c +++ b/menu/drivers_display/menu_display_vulkan.c @@ -53,22 +53,24 @@ static void *menu_display_vk_get_default_mvp(void) 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); } 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; - - vk_t *vk = vk_get_ptr(); + 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(); if (!vk) return; @@ -120,7 +122,8 @@ static void menu_display_vk_draw(void *data) { 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->default_smooth ? vk->samplers.linear : vk->samplers.nearest, mat, @@ -179,14 +182,30 @@ static void menu_display_vk_draw_bg(void *data) static void menu_display_vk_restore_clear_color(void) { - //glClearColor(0.0f, 0.0f, 0.0f, 0.00f); } static void menu_display_vk_clear_color(void *data) { - (void)data; - /* FIXME: This makes little sense in Vulkan. - * We shouldn't be clearing mid-screen nilly willy. */ + VkClearRect rect; + VkClearAttachment attachment = { VK_IMAGE_ASPECT_COLOR_BIT }; + menu_display_ctx_clearcolor_t *clearcolor = + (menu_display_ctx_clearcolor_t*)data; + + vk_t *vk = vk_get_ptr(); + if (!vk || !clearcolor) + return; + + attachment.clearValue.color.float32[0] = clearcolor->r; + attachment.clearValue.color.float32[1] = clearcolor->g; + attachment.clearValue.color.float32[2] = clearcolor->b; + attachment.clearValue.color.float32[3] = clearcolor->a; + + memset(&rect, 0, sizeof(rect)); + rect.rect.extent.width = vk->context->swapchain_width; + rect.rect.extent.height = vk->context->swapchain_height; + rect.layerCount = 1; + + vkCmdClearAttachments(vk->cmd, 1, &attachment, 1, &rect); } static const float *menu_display_vk_get_tex_coords(void) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 991c334eb4..83d346db68 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -628,7 +628,7 @@ static int menu_displaylist_parse_system_info(menu_displaylist_info_t *info) if (gfx_ctx_ctl(GFX_CTL_GET_METRICS, &metrics)) { snprintf(tmp, sizeof(tmp), "%s: %.2f", - menu_hash_to_str(MENU_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH), val); + menu_hash_to_str(MENU_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT), val); menu_entries_push(info->list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0, 0); } diff --git a/qb/config.params.sh b/qb/config.params.sh index 41baddc386..b3c0d2fc23 100644 --- a/qb/config.params.sh +++ b/qb/config.params.sh @@ -71,3 +71,4 @@ HAVE_QT=no # QT companion support HAVE_XSHM=no # XShm video driver support (disabled because it's just a dummied out stub) HAVE_CHEEVOS=yes # Disable Retro Achievements HAVE_VULKAN=auto # Enable Vulkan support +C89_VULKAN=no diff --git a/retroarch.c b/retroarch.c index 07f229fd1b..9fd8db30a0 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1262,7 +1262,6 @@ static int rarch_main_init(int argc, char *argv[]) event_cmd_ctl(EVENT_CMD_CONTROLLERS_INIT, NULL); event_cmd_ctl(EVENT_CMD_RECORD_INIT, NULL); event_cmd_ctl(EVENT_CMD_CHEATS_INIT, NULL); - event_cmd_ctl(EVENT_CMD_REMAPPING_INIT, NULL); event_cmd_ctl(EVENT_CMD_SAVEFILES_INIT, NULL); event_cmd_ctl(EVENT_CMD_SET_PER_GAME_RESOLUTION, NULL); diff --git a/runloop.c b/runloop.c index aa1f5bfae9..5165252d02 100644 --- a/runloop.c +++ b/runloop.c @@ -1446,11 +1446,11 @@ int runloop_iterate(unsigned *sleep_ms) unlock_autosave(); #endif + if (!settings->fastforward_ratio) + return 0; #ifdef HAVE_MENU end: #endif - if (!settings->fastforward_ratio) - return 0; current = retro_get_time_usec(); target = frame_limit_last_time + diff --git a/runloop.h b/runloop.h index 1509707355..1609c8bc3c 100644 --- a/runloop.h +++ b/runloop.h @@ -206,6 +206,7 @@ typedef struct global char ups[PATH_MAX_LENGTH]; char bps[PATH_MAX_LENGTH]; char ips[PATH_MAX_LENGTH]; + char remapfile[PATH_MAX_LENGTH]; } name; /* A list of save types and associated paths for all content. */