Path: blob/master/RSDKv5/RSDK/Graphics/Vulkan/VulkanRenderDevice.cpp
1162 views
#ifdef VK_INTELLISENSE1#include "RetroEngine.hpp"2#include "VulkanRenderDevice.hpp"3#endif45#include <set>6#include <cfloat> // FLT_MAX78// :sob: :sob: :sob:9#include "BackupShaders.hpp"1011#ifdef VK_DEBUG12#define VK_DEBUG_THRESHOLD VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT1314const char *validationLayers[] = { "VK_LAYER_KHRONOS_validation" };1516VKAPI_ATTR VkBool32 VKAPI_CALL RenderDevice::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,17VkDebugUtilsMessageTypeFlagsEXT messageType,18const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData)19{20if (messageSeverity >= VK_DEBUG_THRESHOLD) {21PrintLog(PRINT_NORMAL, "[VK DEBUG] %s", pCallbackData->pMessage);22}2324return VK_FALSE;25}2627VkDebugUtilsMessengerEXT RenderDevice::debugMessenger;28#endif2930const char *requiredExtensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };3132bool RenderDevice::CheckExtensionSupport(VkPhysicalDevice device)33{34uint32_t extensionCount;35vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);3637std::vector<VkExtensionProperties> availableExtensions(extensionCount);38vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());3940std::set<std::string> extensionList(std::begin(requiredExtensions), std::end(requiredExtensions));4142for (const auto &extension : availableExtensions) {43extensionList.erase(extension.extensionName);44}4546return extensionList.empty();47}4849RenderDevice::SwapChainDetails RenderDevice::QuerySwapChainDetails(VkPhysicalDevice device)50{51SwapChainDetails details;5253vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);5455uint32_t formatCount;56vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);5758if (formatCount != 0) {59details.formats.resize(formatCount);60vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());61}6263uint32_t presentModeCount;64vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);6566if (presentModeCount != 0) {67details.presentModes.resize(presentModeCount);68vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());69}7071currentSwapDetails = details;72return details;73}7475bool RenderDevice::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer,76VkDeviceMemory &bufferMemory)77{78VkBufferCreateInfo bufferInfo{};79bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;80bufferInfo.size = size;81bufferInfo.usage = usage;82bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;8384if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {85return false;86}8788VkMemoryRequirements memRequirements;89vkGetBufferMemoryRequirements(device, buffer, &memRequirements);90VkPhysicalDeviceMemoryProperties memProperties;91vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);9293VkMemoryAllocateInfo allocInfo{};94allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;95allocInfo.allocationSize = memRequirements.size;9697allocInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, properties);9899if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {100return false;101}102103vkBindBufferMemory(device, buffer, bufferMemory, 0);104return true;105}106107struct RenderDevice::ShaderConstants {108float2 pixelSize;109float2 textureSize;110float2 viewSize;111#if RETRO_REV02112float screenDim;113#endif114};115116GLFWwindow *RenderDevice::window;117118VkInstance RenderDevice::instance;119VkPhysicalDevice RenderDevice::physicalDevice;120VkDevice RenderDevice::device;121VkSurfaceKHR RenderDevice::surface;122123RenderDevice::SwapChainDetails RenderDevice::currentSwapDetails;124VkSwapchainKHR RenderDevice::swapChain;125VkFormat RenderDevice::swapChainImageFormat;126VkExtent2D RenderDevice::swapChainExtent;127128std::vector<VkImage> RenderDevice::swapChainImages;129std::vector<VkImageView> RenderDevice::swapChainImageViews;130std::vector<VkFramebuffer> RenderDevice::swapChainFramebuffers;131132VkBuffer RenderDevice::uniformBuffer;133VkDeviceMemory RenderDevice::uniformBufferMemory;134RenderDevice::ShaderConstants *RenderDevice::uniformMap;135136VkDescriptorPool RenderDevice::descriptorPool;137VkDescriptorSet RenderDevice::descriptorSet[SCREEN_COUNT];138139VkRenderPass RenderDevice::renderPass;140VkDescriptorSetLayout RenderDevice::setLayout;141VkPipelineLayout RenderDevice::pipelineLayout;142VkGraphicsPipelineCreateInfo RenderDevice::basePipeline;143144VkBuffer RenderDevice::vertexBuffer;145VkDeviceMemory RenderDevice::vertexBufferMemory;146147VkCommandPool RenderDevice::commandPool;148VkCommandBuffer RenderDevice::commandBuffer;149150VkQueue RenderDevice::graphicsQueue;151VkQueue RenderDevice::presentQueue;152uint32 RenderDevice::graphicsIndex;153uint32 RenderDevice::presentIndex;154155VkViewport RenderDevice::viewport;156157VkSemaphore RenderDevice::imageAvailableSemaphore;158VkSemaphore RenderDevice::renderFinishedSemaphore;159VkFence RenderDevice::inFlightFence;160161int32 RenderDevice::monitorIndex;162163VkSampler RenderDevice::samplerPoint;164VkSampler RenderDevice::samplerLinear;165166VkDescriptorImageInfo RenderDevice::imageInfo;167168RenderDevice::Texture RenderDevice::imageTexture;169RenderDevice::Texture RenderDevice::screenTextures[SCREEN_COUNT];170171double RenderDevice::lastFrame;172double RenderDevice::targetFreq;173174//! PIPELINE INFOS175VkPipelineVertexInputStateCreateInfo vertexInputInfo;176VkPipelineInputAssemblyStateCreateInfo inputAssembly;177VkPipelineViewportStateCreateInfo viewportState;178VkPipelineRasterizationStateCreateInfo rasterizer;179VkPipelineDynamicStateCreateInfo dynamicState;180VkDynamicState dynamicStates[1];181VkPipelineColorBlendAttachmentState colorBlendAttachment;182VkPipelineColorBlendStateCreateInfo colorBlending;183VkPipelineMultisampleStateCreateInfo multisampleInfo;184185// Creates a window using the video settings186GLFWwindow *RenderDevice::CreateGLFWWindow(void)187{188GLFWwindow *win;189GLFWmonitor *monitor = NULL;190int32 w, h;191192glfwWindowHint(GLFW_DECORATED, videoSettings.bordered);193194if (videoSettings.windowed) {195w = videoSettings.windowWidth;196h = videoSettings.windowHeight;197}198else if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {199monitor = glfwGetPrimaryMonitor();200const GLFWvidmode *mode = glfwGetVideoMode(monitor);201w = mode->width;202h = mode->height;203}204else {205monitor = glfwGetPrimaryMonitor();206w = videoSettings.fsWidth;207h = videoSettings.fsHeight;208}209210win = glfwCreateWindow(w, h, gameVerInfo.gameTitle, monitor, NULL);211if (!win) {212PrintLog(PRINT_NORMAL, "ERROR: [GLFW] window creation failed");213return NULL;214}215if (videoSettings.windowed) {216// Center the window217monitor = glfwGetPrimaryMonitor();218const GLFWvidmode *mode = glfwGetVideoMode(monitor);219int x, y;220glfwGetMonitorPos(monitor, &x, &y);221// Get scaling for HiDPI screens222float xscale, yscale;223glfwGetMonitorContentScale(monitor, &xscale, &yscale);224int xpos = x + (mode->width - (int)((float)videoSettings.windowWidth * xscale)) / 2;225int ypos = y + (mode->height - (int)((float)videoSettings.windowHeight * yscale)) / 2;226glfwSetWindowPos(win, xpos, ypos);227}228glfwShowWindow(win);229PrintLog(PRINT_NORMAL, "w: %d h: %d windowed: %d", w, h, videoSettings.windowed);230231glfwSetKeyCallback(win, ProcessKeyEvent);232glfwSetMouseButtonCallback(win, ProcessMouseEvent);233glfwSetWindowFocusCallback(win, ProcessFocusEvent);234glfwSetWindowMaximizeCallback(win, ProcessMaximizeEvent);235236return win;237}238239bool RenderDevice::Init()240{241glfwInit();242glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);243glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);244glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);245glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // HiDPI scaling support246#if GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 4247// Disable framebuffer scaling which (surprisingly) makes the framebuffer scale correctly on Wayland248glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);249#endif250251if ((window = CreateGLFWWindow()) == NULL)252return false;253254glfwSetJoystickCallback(ProcessJoystickEvent);255256if (!SetupRendering() || !AudioDevice::Init())257return false;258259InitInputDevices();260return true;261}262263bool RenderDevice::SetupRendering()264{265uint32_t extensionCount = 0;266vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);267PrintLog(PRINT_NORMAL, "[VK] %d extension supported", extensionCount);268269//! DEFINE APP270VkApplicationInfo appInfo{};271appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;272appInfo.pApplicationName = "RSDK" ENGINE_V_NAME;273appInfo.pEngineName = "RSDK" ENGINE_V_NAME;274// i aint trying to populate these vers275appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);276appInfo.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);277appInfo.apiVersion = VK_API_VERSION_1_1;278279VkInstanceCreateInfo instanceInfo{};280instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;281instanceInfo.pApplicationInfo = &appInfo;282283#if VULKAN_USE_GLFW284//! GET REQUIRED GLFW EXTENSIONS285uint32_t glfwExtensionCount = 0;286const char **glfwExtensions;287288glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);289290std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);291#endif292293// some macOS code here might be needed:294// https://vulkan-tutorial.com/en/Drawing_a_triangle/Setup/Instance#page_Encountered-VK_ERROR_INCOMPATIBLE_DRIVER295296#ifndef VK_DEBUG297instanceInfo.enabledLayerCount = 0;298#else299//! VALIDATION LAYERS300uint32_t layerCount;301vkEnumerateInstanceLayerProperties(&layerCount, nullptr);302303std::vector<VkLayerProperties> availableLayers(layerCount);304vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());305306for (const char *layerName : validationLayers) {307for (const auto &layerProperties : availableLayers) {308if (strcmp(layerName, layerProperties.layerName) == 0) {309break;310}311}312313PrintLog(PRINT_NORMAL, "[VK] Requested validation layer %s not found, we won't have it!!!!", layerName);314}315316instanceInfo.enabledLayerCount = sizeof(validationLayers) / sizeof(const char *);317instanceInfo.ppEnabledLayerNames = validationLayers;318319extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);320#endif321322//! CHECK FOR OTHER EXTENSIONS (none required probably)323324instanceInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());325instanceInfo.ppEnabledExtensionNames = extensions.data();326327if (vkCreateInstance(&instanceInfo, nullptr, &instance) != VK_SUCCESS) {328PrintLog(PRINT_NORMAL, "[VK] Could not create instance");329return false;330}331332#if VK_DEBUG333//! SETUP CALLBACK334335VkDebugUtilsMessengerCreateInfoEXT callbackInfo{};336callbackInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;337callbackInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT338| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;339callbackInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT340| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;341callbackInfo.pfnUserCallback = DebugCallback;342callbackInfo.pUserData = nullptr;343344auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");345if (func != nullptr) {346if (func(instance, &callbackInfo, nullptr, &debugMessenger) != VK_SUCCESS) {347PrintLog(PRINT_NORMAL, "[VK] Failed to create debug callback messenger");348return false;349}350}351else {352PrintLog(PRINT_NORMAL, "[VK] Requested debug callback extension not found");353return false;354}355#endif356357//! SURFACE SETUP358#ifdef VULKAN_USE_GLFW359if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {360PrintLog(PRINT_NORMAL, "[VK] Vulkan surface could not be created");361return false;362}363#endif364365//! PICK PHYSICAL DEVICE (we'll settle for any with VK_QUEUE_GRAPHICS_BIT)366physicalDevice = VK_NULL_HANDLE;367uint32_t deviceCount = 0;368vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);369370if (!deviceCount) {371PrintLog(PRINT_NORMAL, "[VK] No GPU with Vulkan support found");372return false;373}374375std::vector<VkPhysicalDevice> devices(deviceCount);376vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());377378// https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families#page_Base-device-suitability-checks379380for (const auto &device : devices) {381if (IsDeviceSuitable(device)) {382physicalDevice = device;383break;384}385}386387if (physicalDevice == VK_NULL_HANDLE) {388PrintLog(PRINT_NORMAL, "[VK] No suitable GPU found (but %d GPUs support Vulkan)", deviceCount);389return false;390}391392std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;393std::set<uint32> uniqueQueueFamilies = { graphicsIndex, presentIndex };394395float queuePriority = 1.0f;396for (uint32_t queueFamily : uniqueQueueFamilies) {397VkDeviceQueueCreateInfo queueCreateInfo{};398queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;399queueCreateInfo.queueFamilyIndex = queueFamily;400queueCreateInfo.queueCount = 1;401queueCreateInfo.pQueuePriorities = &queuePriority;402queueCreateInfos.push_back(queueCreateInfo);403}404405VkPhysicalDeviceFeatures deviceFeatures{};406407VkDeviceCreateInfo deviceInfo{};408deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;409deviceInfo.pQueueCreateInfos = queueCreateInfos.data();410deviceInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());411412deviceInfo.pEnabledFeatures = &deviceFeatures;413414#ifndef VK_DEBUG415deviceInfo.enabledLayerCount = 0;416#else417deviceInfo.enabledLayerCount = sizeof(validationLayers) / sizeof(const char *);418deviceInfo.ppEnabledLayerNames = validationLayers;419#endif420421deviceInfo.enabledExtensionCount = sizeof(requiredExtensions) / sizeof(const char *);422deviceInfo.ppEnabledExtensionNames = requiredExtensions;423424if (vkCreateDevice(physicalDevice, &deviceInfo, nullptr, &device) != VK_SUCCESS) {425PrintLog(PRINT_NORMAL, "[VK] Failed to create device");426return false;427}428429vkGetDeviceQueue(device, graphicsIndex, 0, &graphicsQueue);430vkGetDeviceQueue(device, presentIndex, 0, &presentQueue);431432swapChain = VK_NULL_HANDLE;433434GetDisplays();435436descriptorSet[0] = VK_NULL_HANDLE;437438if (!InitGraphicsAPI() || !InitShaders())439return false;440441int32 size = videoSettings.pixWidth >= SCREEN_YSIZE ? videoSettings.pixWidth : SCREEN_YSIZE;442scanlines = (ScanlineInfo *)malloc(size * sizeof(ScanlineInfo));443memset(scanlines, 0, size * sizeof(ScanlineInfo));444445videoSettings.windowState = WINDOWSTATE_ACTIVE;446videoSettings.dimMax = 1.0;447videoSettings.dimPercent = 1.0;448449return true;450}451452void RenderDevice::GetDisplays()453{454GLFWmonitor *monitor = glfwGetWindowMonitor(window);455if (!monitor)456monitor = glfwGetPrimaryMonitor();457const GLFWvidmode *displayMode = glfwGetVideoMode(monitor);458int32 monitorCount;459GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);460461for (int32 m = 0; m < monitorCount; ++m) {462const GLFWvidmode *vidMode = glfwGetVideoMode(monitors[m]);463displayWidth[m] = vidMode->width;464displayHeight[m] = vidMode->height;465if (!memcmp(vidMode, displayMode, sizeof(GLFWvidmode))) {466monitorIndex = m;467}468}469470const GLFWvidmode *displayModes = glfwGetVideoModes(monitor, &displayCount);471if (displayInfo.displays)472free(displayInfo.displays);473474displayInfo.displays = (decltype(displayInfo.displays))malloc(sizeof(GLFWvidmode) * displayCount);475int32 newDisplayCount = 0;476bool32 foundFullScreenDisplay = false;477478for (int32 d = 0; d < displayCount; ++d) {479memcpy(&displayInfo.displays[newDisplayCount].internal, &displayModes[d], sizeof(GLFWvidmode));480481int32 refreshRate = displayInfo.displays[newDisplayCount].refresh_rate;482if (refreshRate >= 59 && (refreshRate <= 60 || refreshRate >= 120) && displayInfo.displays[newDisplayCount].height >= (SCREEN_YSIZE * 2)) {483if (d && refreshRate == 60 && displayInfo.displays[newDisplayCount - 1].refresh_rate == 59)484--newDisplayCount;485486if (videoSettings.fsWidth == displayInfo.displays[newDisplayCount].width487&& videoSettings.fsHeight == displayInfo.displays[newDisplayCount].height)488foundFullScreenDisplay = true;489490++newDisplayCount;491}492}493494displayCount = newDisplayCount;495if (!foundFullScreenDisplay) {496videoSettings.fsWidth = 0;497videoSettings.fsHeight = 0;498videoSettings.refreshRate = 60; // 0;499}500}501502bool RenderDevice::InitGraphicsAPI()503{504if (videoSettings.windowed || !videoSettings.exclusiveFS) {505if (videoSettings.windowed) {506viewSize.x = videoSettings.windowWidth;507viewSize.y = videoSettings.windowHeight;508}509else {510viewSize.x = displayWidth[monitorIndex];511viewSize.y = displayHeight[monitorIndex];512}513}514else {515int32 bufferWidth = videoSettings.fsWidth;516int32 bufferHeight = videoSettings.fsHeight;517if (videoSettings.fsWidth <= 0 || videoSettings.fsHeight <= 0) {518bufferWidth = displayWidth[monitorIndex];519bufferHeight = displayHeight[monitorIndex];520}521viewSize.x = bufferWidth;522viewSize.y = bufferHeight;523}524525int32 maxPixHeight = 0;526#if !RETRO_USE_ORIGINAL_CODE527int32 screenWidth = 0;528#endif529for (int32 s = 0; s < SCREEN_COUNT; ++s) {530if (videoSettings.pixHeight > maxPixHeight)531maxPixHeight = videoSettings.pixHeight;532533screens[s].size.y = videoSettings.pixHeight;534535float viewAspect = viewSize.x / viewSize.y;536#if !RETRO_USE_ORIGINAL_CODE537screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;538#else539int32 screenWidth = (int32)((viewAspect * videoSettings.pixHeight) + 3) & 0xFFFFFFFC;540#endif541if (screenWidth < videoSettings.pixWidth)542screenWidth = videoSettings.pixWidth;543544#if !RETRO_USE_ORIGINAL_CODE545if (customSettings.maxPixWidth && screenWidth > customSettings.maxPixWidth)546screenWidth = customSettings.maxPixWidth;547#else548if (screenWidth > DEFAULT_PIXWIDTH)549screenWidth = DEFAULT_PIXWIDTH;550#endif551552memset(&screens[s].frameBuffer, 0, sizeof(screens[s].frameBuffer));553SetScreenSize(s, screenWidth, screens[s].size.y);554}555556pixelSize.x = screens[0].size.x;557pixelSize.y = screens[0].size.y;558float pixAspect = pixelSize.x / pixelSize.y;559560Vector2 viewportPos{};561Vector2 lastViewSize;562563glfwGetWindowSize(window, &lastViewSize.x, &lastViewSize.y);564Vector2 viewportSize = lastViewSize;565566if ((viewSize.x / viewSize.y) <= ((pixelSize.x / pixelSize.y) + 0.1)) {567if ((pixAspect - 0.1) > (viewSize.x / viewSize.y)) {568viewSize.y = (pixelSize.y / pixelSize.x) * viewSize.x;569viewportPos.y = (lastViewSize.y >> 1) - (viewSize.y * 0.5);570viewportSize.y = viewSize.y;571}572}573else {574viewSize.x = pixAspect * viewSize.y;575viewportPos.x = (lastViewSize.x >> 1) - ((pixAspect * viewSize.y) * 0.5);576viewportSize.x = (pixAspect * viewSize.y);577}578579#if !RETRO_USE_ORIGINAL_CODE580if (screenWidth <= 512 && maxPixHeight <= 256) {581#else582if (maxPixHeight <= 256) {583#endif584textureSize.x = 512.0;585textureSize.y = 256.0;586}587else {588textureSize.x = 1024.0;589textureSize.y = 512.0;590}591592//! PICK SWAPCHAIN DETAILS593VkSurfaceFormatKHR pickedFormat = currentSwapDetails.formats[0];594VkPresentModeKHR pickedMode = VK_PRESENT_MODE_FIFO_KHR;595VkExtent2D pickedExtent = currentSwapDetails.capabilities.currentExtent;596597for (const auto &availableFormat : currentSwapDetails.formats) {598if ((availableFormat.format == VK_FORMAT_R8G8B8_UNORM || availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM)599&& availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {600pickedFormat = availableFormat;601break;602}603}604605if (!videoSettings.vsync) {606for (const auto &availablePresentMode : currentSwapDetails.presentModes) {607if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {608pickedMode = availablePresentMode;609}610}611}612613pickedExtent = { static_cast<uint32_t>(viewSize.x), static_cast<uint32_t>(viewSize.y) };614615pickedExtent.width =616CLAMP(pickedExtent.width, currentSwapDetails.capabilities.minImageExtent.width, currentSwapDetails.capabilities.maxImageExtent.width);617pickedExtent.height =618CLAMP(pickedExtent.height, currentSwapDetails.capabilities.minImageExtent.height, currentSwapDetails.capabilities.maxImageExtent.height);619620//! CREATE SWAPCHAIN621uint32_t imageCount = currentSwapDetails.capabilities.minImageCount + 1;622if (currentSwapDetails.capabilities.maxImageCount > 0 && imageCount > currentSwapDetails.capabilities.maxImageCount) {623imageCount = currentSwapDetails.capabilities.maxImageCount;624}625626VkSwapchainCreateInfoKHR swapCreateInfo{};627swapCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;628swapCreateInfo.surface = surface;629swapCreateInfo.minImageCount = imageCount;630swapCreateInfo.imageFormat = pickedFormat.format;631swapCreateInfo.imageColorSpace = pickedFormat.colorSpace;632swapCreateInfo.imageExtent = pickedExtent;633swapCreateInfo.imageArrayLayers = 1;634swapCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;635636if (graphicsIndex != presentIndex) {637swapCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;638uint32_t queueFamilyIndices[] = { graphicsIndex, presentIndex };639swapCreateInfo.queueFamilyIndexCount = 2;640swapCreateInfo.pQueueFamilyIndices = queueFamilyIndices;641}642else {643swapCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;644}645646swapCreateInfo.preTransform = currentSwapDetails.capabilities.currentTransform;647swapCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;648swapCreateInfo.presentMode = pickedMode;649swapCreateInfo.clipped = VK_TRUE;650651// swapCreateInfo.oldSwapchain = swapChain;652653if (vkCreateSwapchainKHR(device, &swapCreateInfo, nullptr, &swapChain) != VK_SUCCESS) {654PrintLog(PRINT_NORMAL, "[VK] Failed to create swapchain");655return false;656}657658vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);659swapChainImages.resize(imageCount);660vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());661662swapChainImageFormat = pickedFormat.format;663swapChainExtent = pickedExtent;664665//! CREATE IMAGE VIEWS666swapChainImageViews.resize(swapChainImages.size());667for (int i = 0; i < swapChainImages.size(); i++) {668VkImageViewCreateInfo createInfo{};669createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;670createInfo.image = swapChainImages[i];671createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;672createInfo.format = swapChainImageFormat;673createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;674createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;675createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;676createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;677678createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;679createInfo.subresourceRange.baseMipLevel = 0;680createInfo.subresourceRange.levelCount = 1;681createInfo.subresourceRange.baseArrayLayer = 0;682createInfo.subresourceRange.layerCount = 1;683684if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {685PrintLog(PRINT_NORMAL, "[VK] Failed to create image chain #%d", i);686return false;687}688}689690//! CREATE RENDERPASS691VkAttachmentDescription colorAttachment{};692colorAttachment.format = swapChainImageFormat;693colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;694695colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;696colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;697698colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;699colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;700701colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;702colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;703704VkAttachmentReference colorAttachmentRef{};705colorAttachmentRef.attachment = 0;706colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;707708VkSubpassDescription subpass{};709subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;710711subpass.colorAttachmentCount = 1;712subpass.pColorAttachments = &colorAttachmentRef;713714VkRenderPassCreateInfo renderPassInfo{};715renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;716renderPassInfo.attachmentCount = 1;717renderPassInfo.pAttachments = &colorAttachment;718renderPassInfo.subpassCount = 1;719renderPassInfo.pSubpasses = &subpass;720721if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {722PrintLog(PRINT_NORMAL, "[VK] Failed to create render pass");723}724725//! SET DYNAMIC STATE726dynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT;727728dynamicState = {};729dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;730dynamicState.dynamicStateCount = sizeof(dynamicStates) / sizeof(VkDynamicState);731dynamicState.pDynamicStates = dynamicStates;732733//! SET FIXED FUNCTION CONTROLLERS734inputAssembly = {};735inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;736inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;737inputAssembly.primitiveRestartEnable = VK_FALSE;738739viewport.x = (float)viewportPos.x;740viewport.y = (float)viewportPos.y;741viewport.width = (float)viewportSize.x;742viewport.height = (float)viewportSize.y;743viewport.minDepth = 0.0f;744viewport.maxDepth = 1.0f;745746viewportState = {};747viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;748viewportState.viewportCount = 1;749viewportState.pViewports = &viewport;750viewportState.scissorCount = 1;751viewportState.pScissors = (VkRect2D *)&viewport;752753rasterizer = {};754rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;755rasterizer.depthClampEnable = VK_FALSE;756rasterizer.rasterizerDiscardEnable = VK_FALSE;757rasterizer.lineWidth = 1.0f;758rasterizer.polygonMode = VK_POLYGON_MODE_FILL;759rasterizer.cullMode = VK_CULL_MODE_NONE;760rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;761rasterizer.depthBiasEnable = VK_FALSE;762763colorBlendAttachment = {};764colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;765colorBlendAttachment.blendEnable = VK_FALSE;766767colorBlending = {};768colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;769colorBlending.logicOpEnable = VK_FALSE;770colorBlending.attachmentCount = 1;771colorBlending.pAttachments = &colorBlendAttachment;772773multisampleInfo = {};774multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;775multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;776777//! CREATE UNIFORM AND SAMPLER LAYOUT778VkDescriptorSetLayoutBinding samplerLayoutBinding{};779samplerLayoutBinding.binding = 0;780samplerLayoutBinding.descriptorCount = 1;781samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;782samplerLayoutBinding.pImmutableSamplers = nullptr;783samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;784785VkDescriptorSetLayoutBinding uboLayoutBinding{};786uboLayoutBinding.binding = 1;787uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;788uboLayoutBinding.descriptorCount = 1;789uboLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;790791VkDescriptorSetLayoutBinding bindings[] = { samplerLayoutBinding, uboLayoutBinding };792793VkDescriptorSetLayoutCreateInfo layoutInfo{};794layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;795layoutInfo.bindingCount = 2;796layoutInfo.pBindings = bindings;797798if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &setLayout) != VK_SUCCESS) {799PrintLog(PRINT_NORMAL, "[VK] Failed to create descriptor set layout");800return false;801}802803//! CREATE PIPELINE LAYOUT804VkPipelineLayoutCreateInfo pipelineLayoutInfo{};805pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;806pipelineLayoutInfo.setLayoutCount = 1;807pipelineLayoutInfo.pSetLayouts = &setLayout;808pipelineLayoutInfo.pushConstantRangeCount = 0;809pipelineLayoutInfo.pPushConstantRanges = nullptr;810811if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {812PrintLog(PRINT_NORMAL, "[VK] Failed to create pipeline layout");813return false;814}815816//! CREATE FRAMEBUFFERS817swapChainFramebuffers.resize(swapChainImageViews.size());818for (size_t i = 0; i < swapChainImageViews.size(); i++) {819VkImageView attachments[] = { swapChainImageViews[i] };820821VkFramebufferCreateInfo framebufferInfo{};822framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;823framebufferInfo.renderPass = renderPass;824framebufferInfo.attachmentCount = 1;825framebufferInfo.pAttachments = attachments;826framebufferInfo.width = swapChainExtent.width;827framebufferInfo.height = swapChainExtent.height;828framebufferInfo.layers = 1;829830if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {831PrintLog(PRINT_NORMAL, "[VK] Failed to create framebuffer %d", i);832return false;833}834}835836//! CREATE COMMAND POOL837VkCommandPoolCreateInfo cmdPoolInfo{};838cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;839cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;840cmdPoolInfo.queueFamilyIndex = graphicsIndex;841842if (vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &commandPool) != VK_SUCCESS) {843PrintLog(PRINT_NORMAL, "[VK] Failed to create command pool");844return false;845}846847//! CREATE COMMAND BUFFER848VkCommandBufferAllocateInfo cmdAllocInfo{};849cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;850cmdAllocInfo.commandPool = commandPool;851cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;852cmdAllocInfo.commandBufferCount = 1;853854if (vkAllocateCommandBuffers(device, &cmdAllocInfo, &commandBuffer) != VK_SUCCESS) {855PrintLog(PRINT_NORMAL, "[VK] Failed to create command buffer");856return false;857}858859//! CREATE SYNCHRONIZATION OBJECTS860VkSemaphoreCreateInfo semaphoreInfo{};861semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;862863VkFenceCreateInfo fenceInfo{};864fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;865fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;866867if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS868|| vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore) != VK_SUCCESS869|| vkCreateFence(device, &fenceInfo, nullptr, &inFlightFence) != VK_SUCCESS) {870PrintLog(PRINT_NORMAL, "[VK] Unable to create sephamores");871}872873//! TEXTURE CREATION874for (int32 i = 0; i < SCREEN_COUNT; ++i) {875VkImageCreateInfo imageInfo{};876imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;877imageInfo.imageType = VK_IMAGE_TYPE_2D;878imageInfo.extent.width = static_cast<uint32_t>(textureSize.x);879imageInfo.extent.height = static_cast<uint32_t>(textureSize.y);880imageInfo.extent.depth = 1;881imageInfo.mipLevels = 1;882imageInfo.arrayLayers = 1;883imageInfo.format = VK_FORMAT_R5G6B5_UNORM_PACK16;884imageInfo.tiling = VK_IMAGE_TILING_LINEAR;885imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;886imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;887imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;888imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;889890if (vkCreateImage(device, &imageInfo, nullptr, &screenTextures[i].image) != VK_SUCCESS) {891PrintLog(PRINT_NORMAL, "[VK] Failed to create image for screen texture %d", i);892return false;893}894895VkMemoryRequirements memRequirements;896vkGetImageMemoryRequirements(device, screenTextures[i].image, &memRequirements);897898VkMemoryAllocateInfo allocInfo{};899allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;900allocInfo.allocationSize = memRequirements.size;901allocInfo.memoryTypeIndex =902FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);903904if (vkAllocateMemory(device, &allocInfo, nullptr, &screenTextures[i].memory) != VK_SUCCESS) {905PrintLog(PRINT_NORMAL, "[VK] Failed to allocate memory for screen texture %d", i);906return false;907}908909vkBindImageMemory(device, screenTextures[i].image, screenTextures[i].memory, 0);910vkMapMemory(device, screenTextures[i].memory, 0, memRequirements.size, 0, &screenTextures[i].map);911912VkImageSubresource subresource{};913subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;914915vkGetImageSubresourceLayout(device, screenTextures[i].image, &subresource, &screenTextures[i].layout);916917VkImageViewCreateInfo viewInfo{};918viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;919viewInfo.image = screenTextures[i].image;920viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;921viewInfo.format = VK_FORMAT_R5G6B5_UNORM_PACK16;922viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;923viewInfo.subresourceRange.baseMipLevel = 0;924viewInfo.subresourceRange.levelCount = 1;925viewInfo.subresourceRange.baseArrayLayer = 0;926viewInfo.subresourceRange.layerCount = 1;927928if (vkCreateImageView(device, &viewInfo, nullptr, &screenTextures[i].view) != VK_SUCCESS) {929PrintLog(PRINT_NORMAL, "[VK] Failed to create image view for screen texture %d", i);930return false;931}932933//! TRANSITION TO GENERAL934VkCommandBufferAllocateInfo cmdAllocInfo{};935cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;936cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;937cmdAllocInfo.commandPool = commandPool;938cmdAllocInfo.commandBufferCount = 1;939940VkCommandBuffer commandBuffer;941vkAllocateCommandBuffers(device, &cmdAllocInfo, &commandBuffer);942943VkCommandBufferBeginInfo beginInfo{};944beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;945beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;946947vkBeginCommandBuffer(commandBuffer, &beginInfo);948949VkImageMemoryBarrier barrier{};950barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;951barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;952barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;953barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;954barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;955barrier.image = screenTextures[i].image;956barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;957barrier.subresourceRange.baseMipLevel = 0;958barrier.subresourceRange.levelCount = 1;959barrier.subresourceRange.baseArrayLayer = 0;960barrier.subresourceRange.layerCount = 1;961962VkPipelineStageFlags sourceStage;963VkPipelineStageFlags destinationStage;964965barrier.srcAccessMask = 0;966barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;967968vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,969&barrier);970971vkEndCommandBuffer(commandBuffer);972973VkSubmitInfo submitInfo{};974submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;975submitInfo.commandBufferCount = 1;976submitInfo.pCommandBuffers = &commandBuffer;977978vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);979vkQueueWaitIdle(graphicsQueue);980981vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);982983//! WE DON'T MAKE THE SAMPLER YET984}985986{987//! IMAGE TEXTURE988VkImageCreateInfo imageInfo{};989imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;990imageInfo.imageType = VK_IMAGE_TYPE_2D;991imageInfo.extent.width = RETRO_VIDEO_TEXTURE_W;992imageInfo.extent.height = RETRO_VIDEO_TEXTURE_H;993imageInfo.extent.depth = 1;994imageInfo.mipLevels = 1;995imageInfo.arrayLayers = 1;996imageInfo.format = VK_FORMAT_B8G8R8A8_UNORM;997imageInfo.tiling = VK_IMAGE_TILING_LINEAR;998imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;999imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;1000imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;1001imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;10021003if (vkCreateImage(device, &imageInfo, nullptr, &imageTexture.image) != VK_SUCCESS) {1004PrintLog(PRINT_NORMAL, "[VK] Failed to create image for image texture");1005return false;1006}10071008VkMemoryRequirements memRequirements;1009vkGetImageMemoryRequirements(device, imageTexture.image, &memRequirements);10101011VkMemoryAllocateInfo allocInfo{};1012allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;1013allocInfo.allocationSize = memRequirements.size;1014allocInfo.memoryTypeIndex =1015FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);10161017if (vkAllocateMemory(device, &allocInfo, nullptr, &imageTexture.memory) != VK_SUCCESS) {1018PrintLog(PRINT_NORMAL, "[VK] Failed to allocate memory for image texturre");1019return false;1020}10211022vkBindImageMemory(device, imageTexture.image, imageTexture.memory, 0);1023vkMapMemory(device, imageTexture.memory, 0, memRequirements.size, 0, &imageTexture.map);10241025VkImageSubresource subresource{};1026subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1027vkGetImageSubresourceLayout(device, imageTexture.image, &subresource, &imageTexture.layout);10281029VkImageViewCreateInfo viewInfo{};1030viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;1031viewInfo.image = imageTexture.image;1032viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;1033viewInfo.format = VK_FORMAT_B8G8R8A8_UNORM;1034viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1035viewInfo.subresourceRange.baseMipLevel = 0;1036viewInfo.subresourceRange.levelCount = 1;1037viewInfo.subresourceRange.baseArrayLayer = 0;1038viewInfo.subresourceRange.layerCount = 1;10391040if (vkCreateImageView(device, &viewInfo, nullptr, &imageTexture.view) != VK_SUCCESS) {1041PrintLog(PRINT_NORMAL, "[VK] Failed to create image view for image texture");1042return false;1043}10441045//! TRANSITION TO GENERAL1046VkCommandBufferAllocateInfo cmdAllocInfo{};1047cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;1048cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;1049cmdAllocInfo.commandPool = commandPool;1050cmdAllocInfo.commandBufferCount = 1;10511052VkCommandBuffer commandBuffer;1053vkAllocateCommandBuffers(device, &cmdAllocInfo, &commandBuffer);10541055VkCommandBufferBeginInfo beginInfo{};1056beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;1057beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;10581059vkBeginCommandBuffer(commandBuffer, &beginInfo);10601061VkImageMemoryBarrier barrier{};1062barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;1063barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;1064barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;1065barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1066barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1067barrier.image = imageTexture.image;1068barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1069barrier.subresourceRange.baseMipLevel = 0;1070barrier.subresourceRange.levelCount = 1;1071barrier.subresourceRange.baseArrayLayer = 0;1072barrier.subresourceRange.layerCount = 1;10731074VkPipelineStageFlags sourceStage;1075VkPipelineStageFlags destinationStage;10761077barrier.srcAccessMask = 0;1078barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;10791080vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,1081&barrier);10821083vkEndCommandBuffer(commandBuffer);10841085VkSubmitInfo submitInfo{};1086submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;1087submitInfo.commandBufferCount = 1;1088submitInfo.pCommandBuffers = &commandBuffer;10891090vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);1091vkQueueWaitIdle(graphicsQueue);10921093vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);1094}10951096lastShaderID = -1;10971098InitVertexBuffer();10991100//! CREATE UNIFORM BUFFER1101if (!CreateBuffer(sizeof(ShaderConstants), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,1102VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffer, uniformBufferMemory)) {1103PrintLog(PRINT_NORMAL, "[VK] Failed to create uniform buffer");1104return false;1105}11061107vkMapMemory(device, uniformBufferMemory, 0, sizeof(ShaderConstants), 0, (void **)&uniformMap);11081109//! CREATE FULL BASE PIPELINE1110basePipeline = {};1111basePipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;1112basePipeline.stageCount = 0;1113basePipeline.pStages = nullptr; //! WE FILL THESE LATER!!11141115basePipeline.pVertexInputState = &vertexInputInfo;1116basePipeline.pInputAssemblyState = &inputAssembly;1117basePipeline.pViewportState = &viewportState;1118basePipeline.pRasterizationState = &rasterizer;1119basePipeline.pDynamicState = &dynamicState;1120basePipeline.pColorBlendState = &colorBlending;1121basePipeline.pMultisampleState = &multisampleInfo;1122basePipeline.layout = pipelineLayout;1123basePipeline.renderPass = renderPass;1124basePipeline.subpass = 0;11251126//! CREATE DESCRIPTOR POOL1127VkDescriptorPoolSize poolSizes[] = { {}, {} };1128poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;1129poolSizes[0].descriptorCount = SCREEN_COUNT;1130poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;1131poolSizes[1].descriptorCount = SCREEN_COUNT;11321133VkDescriptorPoolCreateInfo poolInfo{};1134poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;1135poolInfo.poolSizeCount = 2;1136poolInfo.pPoolSizes = poolSizes;1137poolInfo.maxSets = SCREEN_COUNT;1138poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;11391140if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {1141PrintLog(PRINT_NORMAL, "[VK] Failed to create descriptor pool");1142}11431144engine.inFocus = 1;1145videoSettings.viewportX = viewportPos.x;1146videoSettings.viewportY = viewportPos.y;1147videoSettings.viewportW = 1.0 / viewSize.x;1148videoSettings.viewportH = 1.0 / viewSize.y;11491150return true;1151}11521153// CUSTOM BUFFER FOR SHENANIGAN PURPOSES1154// GL hates us and it's coordinate system is reverse of DX1155// for shader output equivalency, we havee to flip everything1156// X and Y are negated, some verts are specifically moved to match1157// U and V are 0/1s and flipped from what it was originally11581159// clang-format off1160#if RETRO_REV021161const RenderVertex rsdkVKVertexBuffer[60] = {1162// 1 Screen (0)1163{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1164{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1165{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1166{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1167{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1168{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },11691170// 2 Screens - Bordered (Top Screen) (6)1171{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1172{ { +0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1173{ { -0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1174{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1175{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1176{ { -0.5, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },11771178// 2 Screens - Bordered (Bottom Screen) (12)1179{ { +0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1180{ { +0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1181{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1182{ { +0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1183{ { -0.5, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1184{ { -0.5, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },11851186// 2 Screens - Stretched (Top Screen) (18)1187{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1188{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1189{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1190{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1191{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1192{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },11931194// 2 Screens - Stretched (Bottom Screen) (24)1195{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1196{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1197{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1198{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1199{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1200{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12011202// 4 Screens (Top-Left) (30)1203{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1204{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1205{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1206{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1207{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1208{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12091210// 4 Screens (Top-Right) (36)1211{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1212{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1213{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1214{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1215{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1216{ { 0.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12171218// 4 Screens (Bottom-Right) (42)1219{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1220{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1221{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1222{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1223{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1224{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12251226// 4 Screens (Bottom-Left) (48)1227{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1228{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1229{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1230{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1231{ { 0.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1232{ { 0.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12331234// Image/Video (54)1235{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1236{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1237{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1238{ { +1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1239{ { -1.0, 1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1240{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }1241};1242#else1243const RenderVertex rsdkVKVertexBuffer[24] =1244{1245// 1 Screen (0)1246{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1247{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1248{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1249{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1250{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1251{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12521253// 2 Screens - Stretched (Top Screen) (6)1254{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1255{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1256{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1257{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1258{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1259{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12601261// 2 Screens - Stretched (Bottom Screen) (12)1262{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1263{ { +1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1264{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1265{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1266{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1267{ { -1.0, 0.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },12681269// Image/Video (18)1270{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1271{ { +1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 0.0 } },1272{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } },1273{ { +1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 1.0, 1.0 } },1274{ { -1.0, -1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 1.0 } },1275{ { -1.0, +1.0, 1.0 }, 0xFFFFFFFF, { 0.0, 0.0 } }1276};1277#endif1278// clang-format on12791280VkVertexInputBindingDescription bindingDescription;1281VkVertexInputAttributeDescription attributeDescriptions[3];12821283bool RenderDevice::InitVertexBuffer()1284{1285RenderVertex vertBuffer[sizeof(rsdkVKVertexBuffer) / sizeof(RenderVertex)];1286memcpy(vertBuffer, rsdkVKVertexBuffer, sizeof(rsdkVKVertexBuffer));12871288float x = 0.5 / (float)viewSize.x;1289float y = 0.5 / (float)viewSize.y;12901291// ignore the last 6 verts, they're scaled to the 1024x512 textures already!1292int32 vertCount = (RETRO_REV02 ? 60 : 24) - 6;1293for (int32 v = 0; v < vertCount; ++v) {1294RenderVertex *vertex = &vertBuffer[v];1295vertex->pos.x = vertex->pos.x + x;1296vertex->pos.y = vertex->pos.y + y;12971298if (vertex->tex.x)1299vertex->tex.x = screens[0].size.x * (1.0 / textureSize.x);13001301if (vertex->tex.y)1302vertex->tex.y = screens[0].size.y * (1.0 / textureSize.y);1303}13041305//! CONFIGURE MEMORY1306if (!CreateBuffer(sizeof(vertBuffer), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,1307VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory)) {1308PrintLog(PRINT_NORMAL, "[VK] Failed to create vertex buffer");1309return false;1310}13111312void *data;1313vkMapMemory(device, vertexBufferMemory, 0, sizeof(vertBuffer), 0, &data);1314memcpy(data, vertBuffer, sizeof(vertBuffer));1315vkUnmapMemory(device, vertexBufferMemory);13161317// remember to bind it later!13181319//! SET VERTEX BINDING DESCRIPTION1320bindingDescription = {};1321bindingDescription.binding = 0;1322bindingDescription.stride = sizeof(RenderVertex);1323bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;13241325//! SET ATTRIBUTE DESCRIPTIONS1326// in_pos1327attributeDescriptions[0] = {};1328attributeDescriptions[0].binding = 0;1329attributeDescriptions[0].location = 0;1330attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;1331attributeDescriptions[0].offset = offsetof(RenderVertex, pos);1332// in_color1333attributeDescriptions[1] = {};1334attributeDescriptions[1].binding = 0;1335attributeDescriptions[1].location = 1;1336attributeDescriptions[1].format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;1337attributeDescriptions[1].offset = offsetof(RenderVertex, color);1338// in_UV1339attributeDescriptions[2] = {};1340attributeDescriptions[2].binding = 0;1341attributeDescriptions[2].location = 2;1342attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;1343attributeDescriptions[2].offset = offsetof(RenderVertex, tex);13441345vertexInputInfo = {};1346vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;1347vertexInputInfo.vertexBindingDescriptionCount = 1;1348vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;1349vertexInputInfo.vertexAttributeDescriptionCount = 3;1350vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions;13511352return true;1353}13541355void RenderDevice::InitFPSCap()1356{1357lastFrame = glfwGetTime();1358targetFreq = 1.0 / videoSettings.refreshRate;1359}1360bool RenderDevice::CheckFPSCap()1361{1362if (lastFrame + targetFreq < glfwGetTime())1363return true;13641365return false;1366}1367void RenderDevice::UpdateFPSCap() { lastFrame = glfwGetTime(); }13681369void RenderDevice::CopyFrameBuffer()1370{1371for (int32 s = 0; s < videoSettings.screenCount; ++s) {1372uint16 *pixels = (uint16 *)screenTextures[s].map;1373uint16 *frameBuffer = screens[s].frameBuffer;13741375int32 screenPitch = screens[s].pitch;1376int32 pitch = (screenTextures[s].layout.rowPitch >> 1) - screenPitch;13771378for (int32 y = 0; y < SCREEN_YSIZE; ++y) {1379int32 pixelCount = screenPitch >> 4;1380for (int32 x = 0; x < pixelCount; ++x) {1381pixels[0] = frameBuffer[0];1382pixels[1] = frameBuffer[1];1383pixels[2] = frameBuffer[2];1384pixels[3] = frameBuffer[3];1385pixels[4] = frameBuffer[4];1386pixels[5] = frameBuffer[5];1387pixels[6] = frameBuffer[6];1388pixels[7] = frameBuffer[7];1389pixels[8] = frameBuffer[8];1390pixels[9] = frameBuffer[9];1391pixels[10] = frameBuffer[10];1392pixels[11] = frameBuffer[11];1393pixels[12] = frameBuffer[12];1394pixels[13] = frameBuffer[13];1395pixels[14] = frameBuffer[14];1396pixels[15] = frameBuffer[15];13971398frameBuffer += 16;1399pixels += 16;1400}14011402pixels += pitch;1403}1404}1405}14061407bool RenderDevice::ProcessEvents()1408{1409glfwPollEvents();1410if (glfwWindowShouldClose(window))1411isRunning = false;1412return false;1413}14141415VkWriteDescriptorSet descriptorWrites[SCREEN_COUNT][2];14161417void RenderDevice::FlipScreen()1418{1419vkWaitForFences(device, 1, &inFlightFence, VK_TRUE, UINT64_MAX);1420vkResetFences(device, 1, &inFlightFence);14211422uint32_t imageIndex;1423VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);14241425if (result == VK_ERROR_OUT_OF_DATE_KHR) {1426// RefreshWindow();1427return;1428} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {1429PrintLog(PRINT_NORMAL, "[VK] Failed to acquire swapchain image");1430return;1431}14321433// Update descriptor textures before the render pass1434switch (videoSettings.screenCount) {1435case 0:1436imageInfo.imageView = imageTexture.view;1437vkUpdateDescriptorSets(device, 2, descriptorWrites[0], 0, nullptr);1438break;1439case 1:1440imageInfo.imageView = screenTextures[0].view;1441vkUpdateDescriptorSets(device, 2, descriptorWrites[0], 0, nullptr);1442break;1443case 2:1444imageInfo.imageView = screenTextures[0].view;1445vkUpdateDescriptorSets(device, 2, descriptorWrites[0], 0, nullptr);1446imageInfo.imageView = screenTextures[1].view;1447vkUpdateDescriptorSets(device, 2, descriptorWrites[1], 0, nullptr);1448break;1449#if RETRO_REV021450case 3:1451imageInfo.imageView = screenTextures[0].view;1452vkUpdateDescriptorSets(device, 2, descriptorWrites[0], 0, nullptr);1453imageInfo.imageView = screenTextures[1].view;1454vkUpdateDescriptorSets(device, 2, descriptorWrites[1], 0, nullptr);1455imageInfo.imageView = screenTextures[2].view;1456vkUpdateDescriptorSets(device, 2, descriptorWrites[2], 0, nullptr);1457break;1458case 4:1459imageInfo.imageView = screenTextures[0].view;1460vkUpdateDescriptorSets(device, 2, descriptorWrites[0], 0, nullptr);1461imageInfo.imageView = screenTextures[1].view;1462vkUpdateDescriptorSets(device, 2, descriptorWrites[1], 0, nullptr);1463imageInfo.imageView = screenTextures[2].view;1464vkUpdateDescriptorSets(device, 2, descriptorWrites[2], 0, nullptr);1465imageInfo.imageView = screenTextures[3].view;1466vkUpdateDescriptorSets(device, 2, descriptorWrites[3], 0, nullptr);1467break;1468#endif1469}14701471vkResetCommandBuffer(commandBuffer, 0);14721473VkCommandBufferBeginInfo beginInfo{};1474beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;1475beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;14761477if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {1478PrintLog(PRINT_NORMAL, "[VK] Failed to begin recording command buffer");1479return;1480}14811482VkRenderPassBeginInfo renderPassInfo{};1483renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;1484renderPassInfo.renderPass = renderPass;1485renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];1486renderPassInfo.renderArea.offset = { 0, 0 };1487renderPassInfo.renderArea.extent = swapChainExtent;14881489VkClearValue clearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };1490renderPassInfo.clearValueCount = 1;1491renderPassInfo.pClearValues = &clearColor;14921493vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);14941495if (lastShaderID != videoSettings.shaderID) {1496lastShaderID = videoSettings.shaderID;14971498imageInfo.sampler = shaderList[videoSettings.shaderID].linear ? samplerLinear : samplerPoint;1499}15001501vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, shaderList[videoSettings.shaderSupport ? videoSettings.shaderID : 0].shaderPipeline);1502vkCmdSetViewport(commandBuffer, 0, 1, &viewport);15031504VkBuffer vertexBuffers[] = { vertexBuffer };1505VkDeviceSize offsets[] = { 0 };1506vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);15071508if (windowRefreshDelay > 0) {1509windowRefreshDelay--;1510if (!windowRefreshDelay)1511UpdateGameWindow();1512return;1513}15141515if (videoSettings.shaderSupport) {1516uniformMap->textureSize = textureSize;1517uniformMap->pixelSize = pixelSize;1518uniformMap->viewSize = viewSize;1519#if RETRO_REV021520uniformMap->screenDim = videoSettings.dimMax * videoSettings.dimPercent;1521#endif1522}15231524int32 startVert = 0;1525switch (videoSettings.screenCount) {1526default:1527case 0:1528#if RETRO_REV021529startVert = 54;1530#else1531startVert = 18;1532#endif1533vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[0], 0, nullptr);1534vkCmdDraw(commandBuffer, 6, 1, startVert, 0);15351536break;15371538case 1:1539vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[0], 0, nullptr);1540vkCmdDraw(commandBuffer, 6, 1, 0, 0);1541break;15421543case 2:1544#if RETRO_REV021545startVert = startVertex_2P[0];1546#else1547startVert = 6;1548#endif1549vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[0], 0, nullptr);1550vkCmdDraw(commandBuffer, 6, 1, startVert, 0);15511552#if RETRO_REV021553startVert = startVertex_2P[1];1554#else1555startVert = 12;1556#endif1557vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[1], 0, nullptr);1558vkCmdDraw(commandBuffer, 6, 1, startVert, 0);1559break;15601561#if RETRO_REV021562case 3:1563vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[0], 0, nullptr);1564vkCmdDraw(commandBuffer, 6, 1, startVertex_3P[0], 0);15651566vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[1], 0, nullptr);1567vkCmdDraw(commandBuffer, 6, 1, startVertex_3P[1], 0);15681569vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[2], 0, nullptr);1570vkCmdDraw(commandBuffer, 6, 1, startVertex_3P[2], 0);1571break;15721573case 4:1574vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[0], 0, nullptr);1575vkCmdDraw(commandBuffer, 6, 1, 30, 0);15761577vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[1], 0, nullptr);1578vkCmdDraw(commandBuffer, 6, 1, 36, 0);15791580vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[2], 0, nullptr);1581vkCmdDraw(commandBuffer, 6, 1, 42, 0);15821583vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet[3], 0, nullptr);1584vkCmdDraw(commandBuffer, 6, 1, 48, 0);1585break;1586#endif1587}15881589vkCmdEndRenderPass(commandBuffer);1590if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {1591PrintLog(PRINT_NORMAL, "[VK] Failed to record command buffer");1592return;1593}15941595VkSubmitInfo submitInfo{};1596submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;15971598VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };1599VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };1600submitInfo.waitSemaphoreCount = 1;1601submitInfo.pWaitSemaphores = waitSemaphores;1602submitInfo.pWaitDstStageMask = waitStages;16031604submitInfo.commandBufferCount = 1;1605submitInfo.pCommandBuffers = &commandBuffer;16061607VkSemaphore signalSemaphores[] = { renderFinishedSemaphore };1608submitInfo.signalSemaphoreCount = 1;1609submitInfo.pSignalSemaphores = signalSemaphores;16101611if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFence) != VK_SUCCESS) {1612PrintLog(PRINT_NORMAL, "[VK] Failed to submit to graphics queue");1613return;1614}16151616VkPresentInfoKHR presentInfo{};1617presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;16181619presentInfo.waitSemaphoreCount = 1;1620presentInfo.pWaitSemaphores = signalSemaphores;16211622VkSwapchainKHR swapChains[] = { swapChain };1623presentInfo.swapchainCount = 1;1624presentInfo.pSwapchains = swapChains;16251626presentInfo.pImageIndices = &imageIndex;16271628vkQueuePresentKHR(presentQueue, &presentInfo);1629}16301631void RenderDevice::ReleaseShaderPipelines()1632{1633vkDeviceWaitIdle(device);16341635for (int32 i = 0; i < shaderCount; ++i) {1636vkDestroyPipeline(device, shaderList[i].shaderPipeline, nullptr);1637}16381639shaderCount = 0;1640#if RETRO_USE_MOD_LOADER1641userShaderCount = 0;1642#endif1643}16441645void RenderDevice::Release(bool32 isRefresh)1646{1647vkDeviceWaitIdle(device);16481649for (auto framebuffer : swapChainFramebuffers) {1650vkDestroyFramebuffer(device, framebuffer, nullptr);1651}16521653for (auto imageView : swapChainImageViews) {1654vkDestroyImageView(device, imageView, nullptr);1655}16561657vkDestroySwapchainKHR(device, swapChain, nullptr);16581659ReleaseShaderPipelines();16601661vkDestroyPipelineLayout(device, pipelineLayout, nullptr);1662vkDestroyRenderPass(device, renderPass, nullptr);16631664vkDestroyBuffer(device, uniformBuffer, nullptr);1665vkFreeMemory(device, uniformBufferMemory, nullptr);16661667for (int32 i = 0; i < SCREEN_COUNT; ++i) {1668vkFreeDescriptorSets(device, descriptorPool, 1, &descriptorSet[i]);1669}1670vkDestroyDescriptorPool(device, descriptorPool, nullptr);1671vkDestroyDescriptorSetLayout(device, setLayout, nullptr);16721673vkDestroySampler(device, samplerPoint, nullptr);1674vkDestroySampler(device, samplerLinear, nullptr);16751676for (int32 i = 0; i < SCREEN_COUNT; ++i) {1677vkDestroyImageView(device, screenTextures[i].view, nullptr);1678vkDestroyImage(device, screenTextures[i].image, nullptr);1679vkUnmapMemory(device, screenTextures[i].memory);1680vkFreeMemory(device, screenTextures[i].memory, nullptr);1681}1682vkDestroyImageView(device, imageTexture.view, nullptr);1683vkDestroyImage(device, imageTexture.image, nullptr);1684vkUnmapMemory(device, imageTexture.memory);1685vkFreeMemory(device, imageTexture.memory, nullptr);16861687vkDestroyBuffer(device, vertexBuffer, nullptr);1688vkFreeMemory(device, vertexBufferMemory, nullptr);16891690vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);1691vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);1692vkDestroyFence(device, inFlightFence, nullptr);16931694vkDestroyCommandPool(device, commandPool, nullptr);16951696vkDestroySurfaceKHR(instance, surface, nullptr);1697glfwDestroyWindow(window);16981699if (!isRefresh) {1700if (displayInfo.displays)1701free(displayInfo.displays);1702displayInfo.displays = NULL;17031704if (scanlines)1705free(scanlines);1706scanlines = NULL;17071708vkDestroyDevice(device, nullptr);17091710#ifdef VK_DEBUG1711auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");1712if (func != nullptr) {1713func(instance, debugMessenger, nullptr);1714}1715#endif17161717vkDestroyInstance(instance, nullptr);17181719glfwTerminate();1720}1721}17221723VkDescriptorBufferInfo bufferInfo{};17241725bool RenderDevice::InitShaders()1726{1727if (descriptorSet[0] == VK_NULL_HANDLE) {1728VkSamplerCreateInfo samplerPointInfo{};1729samplerPointInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;1730samplerPointInfo.magFilter = VK_FILTER_NEAREST;1731samplerPointInfo.minFilter = VK_FILTER_NEAREST;1732samplerPointInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;1733samplerPointInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;1734samplerPointInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;1735samplerPointInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;1736samplerPointInfo.unnormalizedCoordinates = VK_FALSE;1737samplerPointInfo.anisotropyEnable = VK_FALSE;1738samplerPointInfo.maxAnisotropy = 1.0f;1739samplerPointInfo.compareEnable = VK_FALSE;1740samplerPointInfo.compareOp = VK_COMPARE_OP_NEVER;1741samplerPointInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;1742samplerPointInfo.mipLodBias = 0.0f;1743samplerPointInfo.minLod = -FLT_MAX;1744samplerPointInfo.maxLod = FLT_MAX;17451746VkSamplerCreateInfo samplerLinearInfo = samplerPointInfo;1747samplerLinearInfo.magFilter = VK_FILTER_LINEAR;1748samplerLinearInfo.minFilter = VK_FILTER_LINEAR;17491750if (vkCreateSampler(device, &samplerPointInfo, nullptr, &samplerPoint) != VK_SUCCESS) {1751PrintLog(PRINT_NORMAL, "[VK] Failed to create point sampler");1752return false;1753}1754if (vkCreateSampler(device, &samplerLinearInfo, nullptr, &samplerLinear) != VK_SUCCESS) {1755PrintLog(PRINT_NORMAL, "[VK] Failed to create linear sampler");1756return false;1757}17581759// Use the same descriptor set layout for all screens1760VkDescriptorSetLayout layouts[SCREEN_COUNT];1761for (int32 i = 0; i < SCREEN_COUNT; i++) {1762layouts[i] = setLayout;1763}1764//! CREATE DESCRIPTOR SET1765VkDescriptorSetAllocateInfo allocInfo{};1766allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;1767allocInfo.descriptorPool = descriptorPool;1768allocInfo.descriptorSetCount = SCREEN_COUNT;1769allocInfo.pSetLayouts = layouts;17701771if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSet) != VK_SUCCESS) {1772PrintLog(PRINT_NORMAL, "[VK] Failed to allocate descriptor sets");1773return false;1774}17751776//! CREATE DESCRIPTOR SET HERE BC I HAVE VULKAN1777bufferInfo = {};1778bufferInfo.buffer = uniformBuffer;1779bufferInfo.offset = 0;1780bufferInfo.range = sizeof(ShaderConstants);17811782// THIS WILL BE CHANGED REGULARLY1783imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;1784imageInfo.imageView = imageTexture.view;1785imageInfo.sampler = samplerLinear;17861787for (int32 i = 0; i < SCREEN_COUNT; ++i) {1788descriptorWrites[i][0] = {};1789descriptorWrites[i][0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;1790descriptorWrites[i][0].dstSet = descriptorSet[i];1791descriptorWrites[i][0].dstBinding = 0;1792descriptorWrites[i][0].dstArrayElement = 0;1793descriptorWrites[i][0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;1794descriptorWrites[i][0].descriptorCount = 1;1795descriptorWrites[i][0].pImageInfo = &imageInfo;17961797descriptorWrites[i][1] = {};1798descriptorWrites[i][1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;1799descriptorWrites[i][1].dstSet = descriptorSet[i];1800descriptorWrites[i][1].dstBinding = 1;1801descriptorWrites[i][1].dstArrayElement = 0;1802descriptorWrites[i][1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;1803descriptorWrites[i][1].descriptorCount = 1;1804descriptorWrites[i][1].pBufferInfo = &bufferInfo;18051806vkUpdateDescriptorSets(device, 2, descriptorWrites[i], 0, nullptr);1807}1808}18091810// Release old shader pipelines1811if (shaderCount) {1812ReleaseShaderPipelines();1813}18141815videoSettings.shaderSupport = true;1816int32 maxShaders = 0;1817#if RETRO_USE_MOD_LOADER1818shaderCount = 0;1819#endif18201821LoadShader("None", false);1822LoadShader("Clean", true);1823LoadShader("CRT-Yeetron", true);1824LoadShader("CRT-Yee64", true);18251826#if RETRO_USE_MOD_LOADER1827// a place for mods to load custom shaders1828RunModCallbacks(MODCB_ONSHADERLOAD, NULL);1829userShaderCount = shaderCount;1830#endif18311832LoadShader("YUV-420", true);1833LoadShader("YUV-422", true);1834LoadShader("YUV-444", true);1835LoadShader("RGB-Image", true);1836maxShaders = shaderCount;18371838// no shaders == no support1839if (!maxShaders) {1840PrintLog(PRINT_NORMAL, "[VK] No shaders loaded correctly, attempting backup");18411842ShaderEntry *shader = &shaderList[0];1843sprintf_s(shader->name, sizeof(shader->name), "%s", "BACKUP");1844videoSettings.shaderSupport = false;18451846// let's load1847maxShaders = 1;1848shaderCount = 1;18491850VkShaderModule vertModule, fragModule;1851VkShaderModuleCreateInfo createInfo{};1852createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;1853createInfo.codeSize = sizeof(backupVert);1854createInfo.pCode = reinterpret_cast<const uint32_t *>(backupVert);18551856if (vkCreateShaderModule(device, &createInfo, nullptr, &vertModule) != VK_SUCCESS) {1857PrintLog(PRINT_NORMAL, "[VK] Failed to create vertex module for backup shader");1858return false;1859}18601861createInfo.codeSize = sizeof(backupFrag);1862createInfo.pCode = reinterpret_cast<const uint32_t *>(backupFrag);18631864if (vkCreateShaderModule(device, &createInfo, nullptr, &fragModule) != VK_SUCCESS) {1865PrintLog(PRINT_NORMAL, "[VK] Failed to create fragment module for backup shader");1866return false;1867}18681869VkPipelineShaderStageCreateInfo shaderStages[] = { {}, {} };18701871shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1872shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;1873shaderStages[0].module = vertModule;1874shaderStages[0].pName = "main";18751876shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1877shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;1878shaderStages[1].module = fragModule;1879shaderStages[1].pName = "main";18801881VkGraphicsPipelineCreateInfo pipelineInfo = basePipeline;1882pipelineInfo.stageCount = 2;1883pipelineInfo.pStages = shaderStages;18841885if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &shader->shaderPipeline) != VK_SUCCESS) {1886PrintLog(PRINT_NORMAL, "[VK] Failed to create pipeline for backup shader");1887return false;1888}18891890vkDestroyShaderModule(device, fragModule, nullptr);1891vkDestroyShaderModule(device, vertModule, nullptr);18921893shader->linear = videoSettings.windowed ? false : shader->linear;1894}1895videoSettings.shaderID = MAX(videoSettings.shaderID >= maxShaders ? 0 : videoSettings.shaderID, 0);18961897return true;1898}18991900void RenderDevice::LoadShader(const char *fileName, bool32 linear)1901{1902char fullFilePath[0x100];1903FileInfo info;19041905for (int32 i = 0; i < shaderCount; ++i) {1906if (strcmp(shaderList[i].name, fileName) == 0)1907return;1908}19091910if (shaderCount == SHADER_COUNT)1911return;19121913ShaderEntry *shader = &shaderList[shaderCount];1914shader->linear = linear;1915sprintf_s(shader->name, sizeof(shader->name), "%s", fileName);19161917VkShaderModule vertModule, fragModule;19181919sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/CSO-Vulkan/None.vert");1920InitFileInfo(&info);1921if (LoadFile(&info, fullFilePath, FMODE_RB)) {1922uint8 *fileData = NULL;1923AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);1924ReadBytes(&info, fileData, info.fileSize);1925fileData[info.fileSize] = 0;1926CloseFile(&info);19271928VkShaderModuleCreateInfo createInfo{};1929createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;1930createInfo.codeSize = info.fileSize;1931createInfo.pCode = reinterpret_cast<const uint32_t *>(fileData);19321933VkResult res = vkCreateShaderModule(device, &createInfo, nullptr, &vertModule);1934RemoveStorageEntry((void **)&fileData);19351936if (res != VK_SUCCESS) {1937PrintLog(PRINT_NORMAL, "[VK] Failed to create vertex module for %s", shader->name);1938return;1939}1940}1941else1942return;19431944sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/Shaders/CSO-Vulkan/%s.frag", fileName);1945InitFileInfo(&info);1946if (LoadFile(&info, fullFilePath, FMODE_RB)) {1947uint8 *fileData = NULL;1948AllocateStorage((void **)&fileData, info.fileSize + 1, DATASET_TMP, false);1949ReadBytes(&info, fileData, info.fileSize);1950fileData[info.fileSize] = 0;1951CloseFile(&info);19521953VkShaderModuleCreateInfo createInfo{};1954createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;1955createInfo.codeSize = info.fileSize;1956createInfo.pCode = reinterpret_cast<const uint32_t *>(fileData);19571958VkResult res = vkCreateShaderModule(device, &createInfo, nullptr, &fragModule);1959RemoveStorageEntry((void **)&fileData);19601961if (res != VK_SUCCESS) {1962PrintLog(PRINT_NORMAL, "[VK] Failed to create fragment module for %s", shader->name);1963return;1964}1965}1966else1967return;19681969VkPipelineShaderStageCreateInfo shaderStages[] = { {}, {} };19701971shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1972shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;1973shaderStages[0].module = vertModule;1974shaderStages[0].pName = "main";19751976shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1977shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;1978shaderStages[1].module = fragModule;1979shaderStages[1].pName = "main";19801981VkGraphicsPipelineCreateInfo pipelineInfo = basePipeline;1982pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;1983pipelineInfo.stageCount = 2;1984pipelineInfo.pStages = shaderStages;19851986if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &shader->shaderPipeline) != VK_SUCCESS) {1987PrintLog(PRINT_NORMAL, "[VK] Failed to create pipeline for shader %s", shader->name);1988}1989else1990shaderCount++;19911992vkDestroyShaderModule(device, fragModule, nullptr);1993vkDestroyShaderModule(device, vertModule, nullptr);1994};19951996void RenderDevice::RefreshWindow()1997{1998videoSettings.windowState = WINDOWSTATE_UNINITIALIZED;19992000Release(true);2001if ((window = CreateGLFWWindow()) == NULL)2002return;20032004if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {2005PrintLog(PRINT_NORMAL, "[VK] Vulkan surface could not be created");2006return;2007}20082009// Update swapchain details to refresh capabilities ({min/max}ImageExtent)2010QuerySwapChainDetails(physicalDevice);20112012descriptorSet[0] = VK_NULL_HANDLE;20132014if (!InitGraphicsAPI() || !InitShaders())2015return;20162017videoSettings.windowState = WINDOWSTATE_ACTIVE;2018}20192020void RenderDevice::GetWindowSize(int32 *width, int32 *height)2021{2022int32 widest = 0, highest = 0, count = 0;2023GLFWmonitor **monitors = glfwGetMonitors(&count);2024for (int32 i = 0; i < count; i++) {2025const GLFWvidmode *mode = glfwGetVideoMode(monitors[i]);2026if (mode->height > highest) {2027highest = mode->height;2028widest = mode->width;2029}2030}2031if (width)2032*width = widest;2033if (height)2034*height = highest;2035}20362037void RenderDevice::SetupImageTexture(int32 width, int32 height, uint8 *imagePixels)2038{2039uint32 *pixels = (uint32 *)imageTexture.map;2040int32 pitch = (imageTexture.layout.rowPitch >> 2) - width;20412042uint32 *imagePixels32 = (uint32 *)imagePixels;2043for (int32 y = 0; y < height; ++y) {2044for (int32 x = 0; x < width; ++x) {2045*pixels++ = *imagePixels32++;2046}20472048pixels += pitch;2049}2050}20512052void RenderDevice::SetupVideoTexture_YUV420(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,2053int32 strideV)2054{2055uint32 *pixels = (uint32 *)imageTexture.map;2056int32 pitch = (imageTexture.layout.rowPitch >> 2) - width;20572058if (videoSettings.shaderSupport) {2059for (int32 y = 0; y < height; ++y) {2060for (int32 x = 0; x < width; ++x) {2061*pixels++ = (yPlane[x] << 16) | 0xFF000000;2062}20632064pixels += pitch;2065yPlane += strideY;2066}20672068pixels = (uint32 *)imageTexture.map;2069pitch = (imageTexture.layout.rowPitch >> 2) - (width >> 1);2070for (int32 y = 0; y < (height >> 1); ++y) {2071for (int32 x = 0; x < (width >> 1); ++x) {2072*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;2073}20742075pixels += pitch;2076uPlane += strideU;2077vPlane += strideV;2078}2079}2080else {2081// No shader support means no YUV support! at least use the brightness to show it in grayscale!2082for (int32 y = 0; y < height; ++y) {2083for (int32 x = 0; x < width; ++x) {2084int32 brightness = yPlane[x];2085*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;2086}20872088pixels += pitch;2089yPlane += strideY;2090}2091}2092}20932094void RenderDevice::SetupVideoTexture_YUV422(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,2095int32 strideV)2096{2097uint32 *pixels = (uint32 *)imageTexture.map;2098int32 pitch = (imageTexture.layout.rowPitch >> 2) - width;20992100if (videoSettings.shaderSupport) {2101for (int32 y = 0; y < height; ++y) {2102for (int32 x = 0; x < width; ++x) {2103*pixels++ = (yPlane[x] << 16) | 0xFF000000;2104}21052106pixels += pitch;2107yPlane += strideY;2108}21092110pixels = (uint32 *)imageTexture.map;2111pitch = (imageTexture.layout.rowPitch >> 2) - (width >> 1);2112for (int32 y = 0; y < height; ++y) {2113for (int32 x = 0; x < (width >> 1); ++x) {2114*pixels++ |= (vPlane[x] << 0) | (uPlane[x] << 8) | 0xFF000000;2115}21162117pixels += pitch;2118uPlane += strideU;2119vPlane += strideV;2120}2121}2122else {2123// No shader support means no YUV support! at least use the brightness to show it in grayscale!2124for (int32 y = 0; y < height; ++y) {2125for (int32 x = 0; x < width; ++x) {2126int32 brightness = yPlane[x];2127*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;2128}21292130pixels += pitch;2131yPlane += strideY;2132}2133}2134}2135void RenderDevice::SetupVideoTexture_YUV444(int32 width, int32 height, uint8 *yPlane, uint8 *uPlane, uint8 *vPlane, int32 strideY, int32 strideU,2136int32 strideV)2137{2138uint32 *pixels = (uint32 *)imageTexture.map;2139int32 pitch = (imageTexture.layout.rowPitch >> 2) - width;21402141if (videoSettings.shaderSupport) {2142for (int32 y = 0; y < height; ++y) {2143int32 pos1 = yPlane - vPlane;2144int32 pos2 = uPlane - vPlane;2145uint8 *pixV = vPlane;2146for (int32 x = 0; x < width; ++x) {2147*pixels++ = pixV[0] | (pixV[pos2] << 8) | (pixV[pos1] << 16) | 0xFF000000;2148pixV++;2149}21502151pixels += pitch;2152yPlane += strideY;2153uPlane += strideU;2154vPlane += strideV;2155}2156}2157else {2158// No shader support means no YUV support! at least use the brightness to show it in grayscale!2159for (int32 y = 0; y < height; ++y) {2160for (int32 x = 0; x < width; ++x) {2161int32 brightness = yPlane[x];2162*pixels++ = (brightness << 0) | (brightness << 8) | (brightness << 16) | 0xFF000000;2163}21642165pixels += pitch;2166yPlane += strideY;2167}2168}2169}21702171void RenderDevice::ProcessKeyEvent(GLFWwindow *, int32 key, int32 scancode, int32 action, int32 mods)2172{2173switch (action) {2174case GLFW_PRESS: {2175#if !RETRO_REV022176++RSDK::SKU::buttonDownCount;2177#endif2178switch (key) {2179case GLFW_KEY_ENTER:2180if (mods & GLFW_MOD_ALT) {2181videoSettings.windowed ^= 1;2182UpdateGameWindow();2183changedVideoSettings = false;2184break;2185}21862187#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD2188RSDK::SKU::specialKeyStates[1] = true;2189#endif21902191// [fallthrough]21922193default:2194#if RETRO_INPUTDEVICE_KEYBOARD2195SKU::UpdateKeyState(key);2196#endif2197break;21982199case GLFW_KEY_ESCAPE:2200if (engine.devMenu) {2201#if RETRO_REV0U2202if (sceneInfo.state == ENGINESTATE_DEVMENU || RSDK::Legacy::gameMode == RSDK::Legacy::ENGINE_DEVMENU)2203#else2204if (sceneInfo.state == ENGINESTATE_DEVMENU)2205#endif2206CloseDevMenu();2207else2208OpenDevMenu();2209}2210else {2211#if RETRO_INPUTDEVICE_KEYBOARD2212SKU::UpdateKeyState(key);2213#endif2214}22152216#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD2217RSDK::SKU::specialKeyStates[0] = true;2218#endif2219break;22202221#if !RETRO_USE_ORIGINAL_CODE2222case GLFW_KEY_F1:2223if (engine.devMenu) {2224sceneInfo.listPos--;2225while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart2226|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd2227|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {2228sceneInfo.activeCategory--;2229if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {2230sceneInfo.activeCategory = sceneInfo.categoryCount - 1;2231}2232sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd - 1;2233}22342235#if RETRO_REV0U2236switch (engine.version) {2237default: break;2238case 5: LoadScene(); break;2239case 4:2240case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;2241}2242#else2243LoadScene();2244#endif2245}2246break;22472248case GLFW_KEY_F2:2249if (engine.devMenu) {2250sceneInfo.listPos++;2251while (sceneInfo.listPos < sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart2252|| sceneInfo.listPos > sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetEnd2253|| !sceneInfo.listCategory[sceneInfo.activeCategory].sceneCount) {2254sceneInfo.activeCategory++;2255if (sceneInfo.activeCategory >= sceneInfo.categoryCount) {2256sceneInfo.activeCategory = 0;2257}2258sceneInfo.listPos = sceneInfo.listCategory[sceneInfo.activeCategory].sceneOffsetStart;2259}22602261#if RETRO_REV0U2262switch (engine.version) {2263default: break;2264case 5: LoadScene(); break;2265case 4:2266case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;2267}2268#else2269LoadScene();2270#endif2271}2272break;2273#endif22742275case GLFW_KEY_F3:2276if (userShaderCount)2277videoSettings.shaderID = (videoSettings.shaderID + 1) % userShaderCount;2278break;22792280#if !RETRO_USE_ORIGINAL_CODE2281case GLFW_KEY_F4:2282if (engine.devMenu)2283engine.showEntityInfo ^= 1;2284break;22852286case GLFW_KEY_F5:2287if (engine.devMenu) {2288// Quick-Reload2289#if RETRO_USE_MOD_LOADER2290if (mods & GLFW_MOD_CONTROL)2291RefreshModFolders();2292#endif22932294#if RETRO_REV0U2295switch (engine.version) {2296default: break;2297case 5: LoadScene(); break;2298case 4:2299case 3: RSDK::Legacy::stageMode = RSDK::Legacy::STAGEMODE_LOAD; break;2300}2301#else2302LoadScene();2303#endif2304}2305break;23062307case GLFW_KEY_F6:2308if (engine.devMenu && videoSettings.screenCount > 1)2309videoSettings.screenCount--;2310break;23112312case GLFW_KEY_F7:2313if (engine.devMenu && videoSettings.screenCount < SCREEN_COUNT)2314videoSettings.screenCount++;2315break;23162317case GLFW_KEY_F8:2318if (engine.devMenu)2319engine.showUpdateRanges ^= 1;2320break;23212322case GLFW_KEY_F9:2323if (engine.devMenu)2324showHitboxes ^= 1;2325break;23262327case GLFW_KEY_F10:2328if (engine.devMenu)2329engine.showPaletteOverlay ^= 1;2330break;2331#endif2332case GLFW_KEY_BACKSPACE:2333if (engine.devMenu)2334engine.gameSpeed = engine.fastForwardSpeed;2335break;23362337case GLFW_KEY_F11:2338case GLFW_KEY_INSERT:2339if (engine.devMenu)2340engine.frameStep = true;2341break;23422343case GLFW_KEY_F12:2344case GLFW_KEY_PAUSE:2345if (engine.devMenu) {2346#if RETRO_REV0U2347switch (engine.version) {2348default: break;2349case 5:2350if (sceneInfo.state != ENGINESTATE_NONE)2351sceneInfo.state ^= ENGINESTATE_STEPOVER;2352break;2353case 4:2354case 3:2355if (RSDK::Legacy::stageMode != ENGINESTATE_NONE)2356RSDK::Legacy::stageMode ^= RSDK::Legacy::STAGEMODE_STEPOVER;2357break;2358}2359#else2360if (sceneInfo.state != ENGINESTATE_NONE)2361sceneInfo.state ^= ENGINESTATE_STEPOVER;2362#endif2363}2364break;2365}2366break;2367}2368case GLFW_RELEASE: {2369#if !RETRO_REV022370--RSDK::SKU::buttonDownCount;2371#endif2372switch (key) {2373default:2374#if RETRO_INPUTDEVICE_KEYBOARD2375SKU::ClearKeyState(key);2376#endif2377break;23782379#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD2380case GLFW_KEY_ESCAPE:2381RSDK::SKU::specialKeyStates[0] = false;2382SKU::ClearKeyState(key);2383break;23842385case GLFW_KEY_ENTER:2386RSDK::SKU::specialKeyStates[1] = false;2387SKU::ClearKeyState(key);2388break;2389#endif2390case GLFW_KEY_BACKSPACE: engine.gameSpeed = 1; break;2391}2392break;2393}2394}2395}2396void RenderDevice::ProcessFocusEvent(GLFWwindow *, int32 focused)2397{2398if (!focused) {2399#if RETRO_REV022400SKU::userCore->focusState = 1;2401#endif2402}2403else {2404#if RETRO_REV022405SKU::userCore->focusState = 0;2406#endif2407}2408}2409void RenderDevice::ProcessMouseEvent(GLFWwindow *, int32 button, int32 action, int32 mods)2410{2411switch (action) {2412case GLFW_PRESS: {2413switch (button) {2414case GLFW_MOUSE_BUTTON_LEFT: touchInfo.down[0] = true; touchInfo.count = 1;2415#if !RETRO_REV022416RSDK::SKU::buttonDownCount++;2417#endif2418break;24192420case GLFW_MOUSE_BUTTON_RIGHT:2421#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD2422RSDK::SKU::specialKeyStates[3] = true;2423RSDK::SKU::buttonDownCount++;2424#endif2425break;2426}2427break;2428}24292430case GLFW_RELEASE: {2431switch (button) {2432case GLFW_MOUSE_BUTTON_LEFT: touchInfo.down[0] = false; touchInfo.count = 0;2433#if !RETRO_REV022434RSDK::SKU::buttonDownCount--;2435#endif2436break;24372438case GLFW_MOUSE_BUTTON_RIGHT:2439#if !RETRO_REV02 && RETRO_INPUTDEVICE_KEYBOARD2440RSDK::SKU::specialKeyStates[3] = false;2441RSDK::SKU::buttonDownCount--;2442#endif2443break;2444}2445break;2446}2447}2448}2449void RenderDevice::ProcessJoystickEvent(int32 ID, int32 event)2450{2451#if RETRO_INPUTDEVICE_GLFW2452if (!glfwJoystickIsGamepad(ID))2453return;2454uint32 hash;2455char idBuffer[0x20];2456sprintf_s(idBuffer, sizeof(idBuffer), "%s%d", "GLFWDevice", ID);2457GenerateHashCRC(&hash, idBuffer);24582459if (event == GLFW_CONNECTED)2460SKU::InitGLFWInputDevice(hash, ID);2461else2462RemoveInputDevice(InputDeviceFromID(hash));2463#endif2464}2465void RenderDevice::ProcessMaximizeEvent(GLFWwindow *, int32 maximized)2466{2467// i don't know why this is a thing2468if (maximized) {2469// set fullscreen idk about the specifics rn2470}2471}247224732474