diff --git a/core/core.mk b/core/core.mk index befd76563..588fe71ba 100755 --- a/core/core.mk +++ b/core/core.mk @@ -114,14 +114,17 @@ RZDCY_CFLAGS := endif endif -ifdef FOR_WINDOWS - RZDCY_CFLAGS += -DVK_USE_PLATFORM_WIN32_KHR -else - ifdef FOR_ANDROID - RZDCY_CFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR +ifdef USE_VULKAN + ifdef FOR_WINDOWS + RZDCY_CFLAGS += -DVK_USE_PLATFORM_WIN32_KHR else - RZDCY_CFLAGS += -DVK_USE_PLATFORM_XLIB_KHR + ifdef FOR_ANDROID + RZDCY_CFLAGS += -DVK_USE_PLATFORM_ANDROID_KHR + else + RZDCY_CFLAGS += -DVK_USE_PLATFORM_XLIB_KHR + endif endif + RZDCY_CFLAGS += -D USE_VULKAN endif RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR) -I$(RZDCY_SRC_DIR)/rend/gles -I$(RZDCY_SRC_DIR)/deps \ diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp index 5e46549dd..c09002782 100644 --- a/core/rend/TexCache.cpp +++ b/core/rend/TexCache.cpp @@ -651,7 +651,8 @@ void BaseTextureCacheData::Update() * settings.rend.MaxFilteredTextureSize // Don't process textures that are too big || tcw.PixelFmt == PixelYUV) // Don't process YUV textures && (!IsPaletted() || tex_type != TextureType::_8888) - && texconv != NULL) + && texconv != NULL + && !Force32BitTexture(tex_type)) need_32bit_buffer = false; // TODO avoid upscaling/depost. textures that change too often diff --git a/core/rend/TexCache.h b/core/rend/TexCache.h index a8b146917..a5176993b 100644 --- a/core/rend/TexCache.h +++ b/core/rend/TexCache.h @@ -4,6 +4,7 @@ #include #include "oslib/oslib.h" #include "hw/pvr/pvr_regs.h" +#undef ID #include "hw/pvr/ta_structs.h" extern u8* vq_codebook; @@ -697,6 +698,7 @@ struct BaseTextureCacheData void ComputeHash(); void Update(); virtual void UploadToGPU(int width, int height, u8 *temp_tex_buffer) = 0; + virtual bool Force32BitTexture(TextureType type) { return false; } void CheckCustomTexture(); //true if : dirty or paletted texture and hashes don't match bool NeedsUpdate(); diff --git a/core/rend/vulkan/buffer.h b/core/rend/vulkan/buffer.h index 6a9d24399..efe301136 100644 --- a/core/rend/vulkan/buffer.h +++ b/core/rend/vulkan/buffer.h @@ -54,7 +54,8 @@ struct BufferData void* dataPtr = device.mapMemory(sharedDeviceMemory, offset + bufOffset, totalSize); for (int i = 0; i < count; i++) { - memcpy(dataPtr, data[i], sizes[i]); + if (data[i] != nullptr) + memcpy(dataPtr, data[i], sizes[i]); dataPtr = (u8 *)dataPtr + sizes[i]; } device.unmapMemory(sharedDeviceMemory); diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index d9a28d1ce..99572e59c 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -181,9 +181,8 @@ void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int coun if (count == 0 || pvrrc.modtrig.used() == 0) return; - vk::DeviceSize offsets[] = { (vk::DeviceSize)pvrrc.verts.bytes() }; vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); - cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); + cmdBuffer.bindVertexBuffers(0, 1, &buffer, &offsets.modVolOffset); ModifierVolumeParam* params = &pvrrc.global_param_mvo.head()[first]; @@ -218,8 +217,8 @@ void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int coun mod_base = -1; } } - offsets[0] = 0; - cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); + const vk::DeviceSize offset = 0; + cmdBuffer.bindVertexBuffers(0, 1, &buffer, &offset); std::array pushConstants = { 1 - FPU_SHAD_SCALE.scale_factor / 256.f, 0, 0, 0, 0 }; cmdBuffer.pushConstants(pipelineManager->GetPipelineLayout(), vk::ShaderStageFlagBits::eFragment, 0, pushConstants); @@ -229,20 +228,30 @@ void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int coun cmdBuffer.drawIndexed(4, 1, 0, 0, 0); } -void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms, u32& vertexUniformsOffset) +void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms) { - vertexUniformsOffset = pvrrc.verts.bytes() + pvrrc.idx.bytes() + pvrrc.modtrig.bytes() + sortedIndexCount * sizeof(u32); - u32 totalSize = vertexUniformsOffset + sizeof(VertexShaderUniforms) + sizeof(FragmentShaderUniforms); - - BufferData *buffer = GetMainBuffer(totalSize); - + // TODO Put this logic in an allocator std::vector chunks; std::vector chunkSizes; + // Vertex chunks.push_back(pvrrc.verts.head()); chunkSizes.push_back(pvrrc.verts.bytes()); + + u32 padding = align(pvrrc.verts.bytes(), 4); + offsets.modVolOffset = pvrrc.verts.bytes() + padding; + chunks.push_back(nullptr); + chunkSizes.push_back(padding); + + // Modifier Volumes chunks.push_back(pvrrc.modtrig.head()); chunkSizes.push_back(pvrrc.modtrig.bytes()); + padding = align(offsets.modVolOffset + pvrrc.modtrig.bytes(), 4); + offsets.indexOffset = offsets.modVolOffset + pvrrc.modtrig.bytes() + padding; + chunks.push_back(nullptr); + chunkSizes.push_back(padding); + + // Index chunks.push_back(pvrrc.idx.head()); chunkSizes.push_back(pvrrc.idx.bytes()); for (const std::vector& idx : sortedIndexes) @@ -253,10 +262,25 @@ void Drawer::UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const chunkSizes.push_back(idx.size() * sizeof(u32)); } } + // Uniform buffers + u32 indexSize = pvrrc.idx.bytes() + sortedIndexCount * sizeof(u32); + padding = align(offsets.indexOffset + indexSize, std::max(4, (int)GetContext()->GetUniformBufferAlignment())); + offsets.vertexUniformOffset = offsets.indexOffset + indexSize + padding; + chunks.push_back(nullptr); + chunkSizes.push_back(padding); + chunks.push_back(&vertexUniforms); chunkSizes.push_back(sizeof(vertexUniforms)); + padding = align(offsets.vertexUniformOffset + sizeof(VertexShaderUniforms), std::max(4, (int)GetContext()->GetUniformBufferAlignment())); + offsets.fragmentUniformOffset = offsets.vertexUniformOffset + sizeof(VertexShaderUniforms) + padding; + chunks.push_back(nullptr); + chunkSizes.push_back(padding); + chunks.push_back(&fragmentUniforms); chunkSizes.push_back(sizeof(fragmentUniforms)); + u32 totalSize = offsets.fragmentUniformOffset + sizeof(FragmentShaderUniforms); + + BufferData *buffer = GetMainBuffer(totalSize); buffer->upload(GetContext()->GetDevice().get(), chunks.size(), &chunkSizes[0], &chunks[0]); } @@ -376,20 +400,19 @@ bool Drawer::Draw(const Texture *fogTexture) vk::CommandBuffer cmdBuffer = BeginRenderPass(); // Upload vertex and index buffers - u32 vertexUniformsOffset; - UploadMainBuffer(vtxUniforms, fragUniforms, vertexUniformsOffset); + UploadMainBuffer(vtxUniforms, fragUniforms); // Update per-frame descriptor set and bind it - GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), vertexUniformsOffset, fogTexture->GetImageView()); + GetCurrentDescSet().UpdateUniforms(GetMainBuffer(0)->buffer.get(), offsets.vertexUniformOffset, offsets.fragmentUniformOffset, fogTexture->GetImageView()); GetCurrentDescSet().BindPerFrameDescriptorSets(cmdBuffer); // Reset per-poly descriptor set pool GetCurrentDescSet().Reset(); // Bind vertex and index buffers - const vk::DeviceSize offsets[] = { 0 }; + const vk::DeviceSize zeroOffset[] = { 0 }; const vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); - cmdBuffer.bindVertexBuffers(0, 1, &buffer, offsets); - cmdBuffer.bindIndexBuffer(buffer, pvrrc.verts.bytes() + pvrrc.modtrig.bytes(), vk::IndexType::eUint32); + cmdBuffer.bindVertexBuffers(0, 1, &buffer, zeroOffset); + cmdBuffer.bindIndexBuffer(buffer, offsets.indexOffset, vk::IndexType::eUint32); RenderPass previous_pass = {}; for (int render_pass = 0; render_pass < pvrrc.render_passes.used(); render_pass++) diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index e0e9d7017..f3fbbaaec 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -80,8 +80,18 @@ private: void DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector& polys); void DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List& polys, u32 first, u32 count); void DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count); - void UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms, u32& vertexUniformsOffset); + void UploadMainBuffer(const VertexShaderUniforms& vertexUniforms, const FragmentShaderUniforms& fragmentUniforms); + u32 align(vk::DeviceSize offset, u32 alignment) + { + return (u32)(alignment - (offset & (alignment - 1))); + } + struct { + vk::DeviceSize indexOffset = 0; + vk::DeviceSize modVolOffset = 0; + vk::DeviceSize vertexUniformOffset = 0; + vk::DeviceSize fragmentUniformOffset = 0; + } offsets; // Per-triangle sort results std::vector> sortedPolys; std::vector> sortedIndexes; diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h index 0fc052d19..70b319907 100644 --- a/core/rend/vulkan/pipeline.h +++ b/core/rend/vulkan/pipeline.h @@ -37,7 +37,7 @@ public: this->perPolyLayout = perPolyLayout; } - void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, vk::ImageView fogImageView) + void UpdateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, u32 fragmentUniformOffset, vk::ImageView fogImageView) { if (!perFrameDescSet) { @@ -46,7 +46,7 @@ public: } std::vector bufferInfos; bufferInfos.push_back(vk::DescriptorBufferInfo(buffer, vertexUniformOffset, sizeof(VertexShaderUniforms))); - bufferInfos.push_back(vk::DescriptorBufferInfo(buffer, vertexUniformOffset + sizeof(VertexShaderUniforms), sizeof(FragmentShaderUniforms))); + bufferInfos.push_back(vk::DescriptorBufferInfo(buffer, fragmentUniformOffset, sizeof(FragmentShaderUniforms))); std::vector writeDescriptorSets; writeDescriptorSets.push_back(vk::WriteDescriptorSet(*perFrameDescSet, 0, 0, 1, vk::DescriptorType::eUniformBuffer, nullptr, &bufferInfos[0], nullptr)); @@ -275,7 +275,7 @@ public: }; rttRenderPass = GetContext()->GetDevice()->createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), 2, attachmentDescriptions, - 1, &subpass, ARRAY_SIZE(settings.rend.RenderToTextureBuffer ? vramWriteDeps : dependencies), + 1, &subpass, settings.rend.RenderToTextureBuffer ? ARRAY_SIZE(vramWriteDeps) : ARRAY_SIZE(dependencies), settings.rend.RenderToTextureBuffer ? vramWriteDeps : dependencies)); renderPass = *rttRenderPass; printf("RttPipelineManager renderPass %p created\n", (VkRenderPass)renderPass); diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp index beefed3c9..f99f83026 100644 --- a/core/rend/vulkan/texture.cpp +++ b/core/rend/vulkan/texture.cpp @@ -177,14 +177,13 @@ void Texture::Init(u32 width, u32 height, vk::Format format) vk::FormatFeatureFlags formatFeatureFlags = vk::FormatFeatureFlagBits::eSampledImage; // Forcing staging since it fixes texture glitches - needsStaging = true; //(formatProperties.linearTilingFeatures & formatFeatureFlags) != formatFeatureFlags; + needsStaging = (formatProperties.optimalTilingFeatures & formatFeatureFlags) == formatFeatureFlags; vk::ImageTiling imageTiling; vk::ImageLayout initialLayout; vk::MemoryPropertyFlags requirements; vk::ImageUsageFlags usageFlags = vk::ImageUsageFlagBits::eSampled; if (needsStaging) { - verify((formatProperties.optimalTilingFeatures & formatFeatureFlags) == formatFeatureFlags); if (allocator) stagingBufferData = std::unique_ptr(new BufferData(physicalDevice, device, extent.width * extent.height * 4, vk::BufferUsageFlagBits::eTransferSrc, allocator)); else @@ -196,6 +195,7 @@ void Texture::Init(u32 width, u32 height, vk::Format format) } else { + verify((formatProperties.linearTilingFeatures & formatFeatureFlags) == formatFeatureFlags); imageTiling = vk::ImageTiling::eLinear; initialLayout = vk::ImageLayout::ePreinitialized; requirements = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible; diff --git a/core/rend/vulkan/texture.h b/core/rend/vulkan/texture.h index a8fb79e81..f3de8a44c 100644 --- a/core/rend/vulkan/texture.h +++ b/core/rend/vulkan/texture.h @@ -45,6 +45,7 @@ struct Texture : BaseTextureCacheData bool IsNew() const { return !image.get(); } vk::ImageView GetImageView() const { return *imageView; } void SetCommandBuffer(vk::CommandBuffer commandBuffer) { this->commandBuffer = commandBuffer; } + virtual bool Force32BitTexture(TextureType type) override { return !VulkanContext::Instance()->IsFormatSupported(type); } private: void Init(u32 width, u32 height, vk::Format format); diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h index 8c6cd9344..bbc4c23da 100644 --- a/core/rend/vulkan/vulkan.h +++ b/core/rend/vulkan/vulkan.h @@ -24,8 +24,9 @@ #include "volk/volk.h" #undef VK_NO_PROTOTYPES #include "vulkan/vulkan.hpp" +#include "rend/TexCache.h" -#define VK_DEBUG +//#define VK_DEBUG extern int screen_width, screen_height; @@ -34,8 +35,8 @@ class VulkanContext public: VulkanContext() { verify(contextInstance == nullptr); contextInstance = this; } ~VulkanContext(); - void InitInstance(const char** extensions, uint32_t extensions_count); - void InitDevice(); + bool InitInstance(const char** extensions, uint32_t extensions_count); + bool InitDevice(); void CreateSwapChain(); VkInstance GetInstance() const { return static_cast(instance.get()); } @@ -61,6 +62,23 @@ public: void WaitIdle() const { graphicsQueue.waitIdle(); } bool IsRendering() const { return rendering; } vk::Queue GetGraphicsQueue() const { return graphicsQueue; } + vk::DeviceSize GetUniformBufferAlignment() const { return uniformBufferAlignment; } + bool IsFormatSupported(TextureType textureType) + { + switch (textureType) + { + case TextureType::_4444: + return optimalTilingSupported4444; + case TextureType::_565: + return optimalTilingSupported565; + case TextureType::_5551: + return optimalTilingSupported1555; + default: + return true; + } + } + std::string GetDriverName() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return props.deviceName; } + std::string GetDriverVersion() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return std::to_string(props.driverVersion); } static VulkanContext *Instance() { return contextInstance; } @@ -101,6 +119,10 @@ private: u32 graphicsQueueIndex = 0; u32 presentQueueIndex = 0; + vk::DeviceSize uniformBufferAlignment = 0; + bool optimalTilingSupported565 = false; + bool optimalTilingSupported1555 = false; + bool optimalTilingSupported4444 = false; vk::UniqueDevice device; vk::SurfaceKHR surface; @@ -131,7 +153,11 @@ private: vk::UniquePipelineCache pipelineCache; #ifdef VK_DEBUG +#ifndef __ANDROID__ vk::UniqueDebugUtilsMessengerEXT debugUtilsMessenger; +#else + vk::UniqueDebugReportCallbackEXT debugReportCallback; +#endif #endif static VulkanContext *contextInstance; }; diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index f0b086145..918d768a1 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -28,6 +28,10 @@ VulkanContext *VulkanContext::contextInstance; static const char *PipelineCacheFileName = DATA_PATH "vulkan_pipeline.cache"; +#if HOST_CPU == CPU_ARM +__attribute__((pcs("aapcs-vfp"))) +#endif +#ifndef __ANDROID__ static VkBool32 debugUtilsMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, VkDebugUtilsMessengerCallbackDataEXT const * pCallbackData, void * /*pUserData*/) { @@ -86,6 +90,23 @@ static VkBool32 debugUtilsMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsE } return VK_TRUE; } +#else +static VkBool32 debugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, + const char* pLayerPrefix, const char* pMessage, void* /*pUserData*/) +{ + std::string msg = pMessage; + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) + ERROR_LOG(RENDERER, "%s", msg.c_str()); + else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) + WARN_LOG(RENDERER, "%s", msg.c_str()); + else if (flags & (VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT)) + NOTICE_LOG(RENDERER, "%s", msg.c_str()); + else + NOTICE_LOG(RENDERER, "(d) %s", msg.c_str()); + + return VK_FALSE; +} +#endif static void CheckImGuiResult(VkResult err) { @@ -93,10 +114,13 @@ static void CheckImGuiResult(VkResult err) WARN_LOG(RENDERER, "ImGui Vulkan error %d", err); } -void VulkanContext::InitInstance(const char** extensions, uint32_t extensions_count) +bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_count) { if (volkInitialize() != VK_SUCCESS) - return; + { + ERROR_LOG(RENDERER, "Cannot load Vulkan libraries"); + return false; + } try { vk::ApplicationInfo applicationInfo("Flycast", 1, "Flycast", 1, VK_API_VERSION_1_0); @@ -106,6 +130,7 @@ void VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co std::vector layer_names; #ifdef VK_DEBUG +#ifndef __ANDROID__ vext.push_back("VK_EXT_debug_utils"); extensions_count += 1; // layer_names.push_back("VK_LAYER_GOOGLE_unique_objects"); @@ -117,6 +142,15 @@ void VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co // layer_names.push_back("VK_LAYER_LUNARG_swapchain"); // layer_names.push_back("VK_LAYER_GOOGLE_threading"); layer_names.push_back("VK_LAYER_LUNARG_standard_validation"); +#else + vext.push_back("VK_EXT_debug_report"); // NDK <= 19? + extensions_count += 1; + layer_names.push_back("VK_LAYER_GOOGLE_threading"); + layer_names.push_back("VK_LAYER_LUNARG_parameter_validation"); + layer_names.push_back("VK_LAYER_LUNARG_object_tracker"); + layer_names.push_back("VK_LAYER_LUNARG_core_validation"); + layer_names.push_back("VK_LAYER_GOOGLE_unique_objects"); +#endif #endif extensions = &vext[0]; vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, layer_names.size(), &layer_names[0], extensions_count, extensions); @@ -126,14 +160,42 @@ void VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co volkLoadInstance(static_cast(*instance)); #ifdef VK_DEBUG +#ifndef __ANDROID__ vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError); vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation); - debugUtilsMessenger = instance->createDebugUtilsMessengerEXTUnique(vk::DebugUtilsMessengerCreateInfoEXT({}, severityFlags, messageTypeFlags, &debugUtilsMessengerCallback)); + debugUtilsMessenger = instance->createDebugUtilsMessengerEXTUnique(vk::DebugUtilsMessengerCreateInfoEXT({}, severityFlags, messageTypeFlags, debugUtilsMessengerCallback)); +#else + vk::DebugReportCallbackCreateInfoEXT createInfo(vk::DebugReportFlagBitsEXT::eDebug | vk::DebugReportFlagBitsEXT::eInformation + | vk::DebugReportFlagBitsEXT::ePerformanceWarning | vk::DebugReportFlagBitsEXT::eWarning + | vk::DebugReportFlagBitsEXT::eError, &::debugReportCallback); + debugReportCallback = instance->createDebugReportCallbackEXTUnique(createInfo); +#endif #endif physicalDevice = instance->enumeratePhysicalDevices().front(); + vk::PhysicalDeviceProperties properties; + physicalDevice.getProperties(&properties); + uniformBufferAlignment = properties.limits.minUniformBufferOffsetAlignment; + + vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(vk::Format::eR5G5B5A1UnormPack16); + if (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) + optimalTilingSupported1555 = true; + else + NOTICE_LOG(RENDERER, "eR5G5B5A1UnormPack16 not supported for optimal tiling"); + formatProperties = physicalDevice.getFormatProperties(vk::Format::eR5G6B5UnormPack16); + if (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) + optimalTilingSupported565 = true; + else + NOTICE_LOG(RENDERER, "eR5G6B5UnormPack16 not supported for optimal tiling"); + formatProperties = physicalDevice.getFormatProperties(vk::Format::eR4G4B4A4UnormPack16); + if (formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) + optimalTilingSupported4444 = true; + else + NOTICE_LOG(RENDERER, "eR4G4B4A4UnormPack16 not supported for optimal tiling"); + + return true; } catch (const vk::SystemError& err) { @@ -143,6 +205,7 @@ void VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co { ERROR_LOG(RENDERER, "Unknown error"); } + return false; } vk::Format VulkanContext::InitDepthBuffer() @@ -204,18 +267,18 @@ void VulkanContext::InitImgui() { gui_init(); ImGui_ImplVulkan_InitInfo initInfo = {}; - initInfo.Instance = *instance; - initInfo.PhysicalDevice = physicalDevice; - initInfo.Device = *device; + initInfo.Instance = (VkInstance)*instance; + initInfo.PhysicalDevice = (VkPhysicalDevice)physicalDevice; + initInfo.Device = (VkDevice)*device; initInfo.QueueFamily = graphicsQueueIndex; - initInfo.Queue = graphicsQueue; - initInfo.PipelineCache = *pipelineCache; - initInfo.DescriptorPool = *descriptorPool; + initInfo.Queue = (VkQueue)graphicsQueue; + initInfo.PipelineCache = (VkPipelineCache)*pipelineCache; + initInfo.DescriptorPool = (VkDescriptorPool)*descriptorPool; #ifdef VK_DEBUG initInfo.CheckVkResultFn = &CheckImGuiResult; #endif - if (!ImGui_ImplVulkan_Init(&initInfo, *renderPass)) + if (!ImGui_ImplVulkan_Init(&initInfo, (VkRenderPass)*renderPass)) { die("ImGui initialization failed"); } @@ -224,7 +287,7 @@ void VulkanContext::InitImgui() device->resetCommandPool(*commandPools.front(), vk::CommandPoolResetFlagBits::eReleaseResources); vk::CommandBuffer& commandBuffer = *commandBuffers.front(); commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - ImGui_ImplVulkan_CreateFontsTexture(commandBuffer); + ImGui_ImplVulkan_CreateFontsTexture((VkCommandBuffer)commandBuffer); commandBuffer.end(); vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer); graphicsQueue.submit(1, &submitInfo, *drawFences.front()); @@ -233,8 +296,10 @@ void VulkanContext::InitImgui() ImGui_ImplVulkan_InvalidateFontUploadObjects(); } -void VulkanContext::InitDevice() +bool VulkanContext::InitDevice() { + if (!instance) + return false; try { std::vector queueFamilyProperties = physicalDevice.getQueueFamilyProperties(); @@ -303,7 +368,7 @@ void VulkanContext::InitDevice() vk::DescriptorPoolSize pool_sizes[] = { { vk::DescriptorType::eSampler, 2 }, - { vk::DescriptorType::eCombinedImageSampler, 2000 }, + { vk::DescriptorType::eCombinedImageSampler, 4000 }, { vk::DescriptorType::eSampledImage, 2 }, { vk::DescriptorType::eStorageImage, 2 }, { vk::DescriptorType::eUniformTexelBuffer, 2 }, @@ -336,6 +401,8 @@ void VulkanContext::InitDevice() } CreateSwapChain(); + + return true; } catch (const vk::SystemError& err) { @@ -345,6 +412,7 @@ void VulkanContext::InitDevice() { ERROR_LOG(RENDERER, "Unknown error"); } + return false; } void VulkanContext::CreateSwapChain() @@ -369,7 +437,7 @@ void VulkanContext::CreateSwapChain() { DEBUG_LOG(RENDERER, "Supported surface format: %s", vk::to_string(f.format).c_str()); // Try to find an non-sRGB color format - if (f.format == vk::Format::eB8G8R8A8Unorm) + if (f.format == vk::Format::eB8G8R8A8Unorm || f.format == vk::Format::eR8G8B8A8Unorm) { colorFormat = f.format; break; @@ -434,6 +502,7 @@ void VulkanContext::CreateSwapChain() swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; } + swapChain.reset(); swapChain = device->createSwapchainKHRUnique(swapChainCreateInfo); std::vector swapChainImages = device->getSwapchainImagesKHR(*swapChain); @@ -557,19 +626,21 @@ void VulkanContext::Present() VulkanContext::~VulkanContext() { - printf("VulkanContext::~VulkanContext\n"); ImGui_ImplVulkan_Shutdown(); - std::vector cacheData = device->getPipelineCacheData(*pipelineCache); - if (!cacheData.empty()) - { - std::string cachePath = get_writable_data_path(PipelineCacheFileName); - FILE *f = fopen(cachePath.c_str(), "wb"); - if (f != nullptr) - { - (void)fwrite(&cacheData[0], 1, cacheData.size(), f); - fclose(f); - } - } + if (device) + { + std::vector cacheData = device->getPipelineCacheData(*pipelineCache); + if (!cacheData.empty()) + { + std::string cachePath = get_writable_data_path(PipelineCacheFileName); + FILE *f = fopen(cachePath.c_str(), "wb"); + if (f != nullptr) + { + (void)fwrite(&cacheData[0], 1, cacheData.size(), f); + fclose(f); + } + } + } swapChain.reset(); imageViews.clear(); framebuffers.clear(); @@ -583,7 +654,8 @@ VulkanContext::~VulkanContext() imageAcquiredSemaphores.clear(); renderCompleteSemaphores.clear(); drawFences.clear(); - vkDestroySurfaceKHR((VkInstance)*instance, (VkSurfaceKHR)surface, nullptr); + if (surface) + vkDestroySurfaceKHR((VkInstance)*instance, (VkSurfaceKHR)surface, nullptr); verify(contextInstance == this); contextInstance = nullptr; diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp index d1d43c9e2..32e611455 100644 --- a/core/rend/vulkan/vulkan_renderer.cpp +++ b/core/rend/vulkan/vulkan_renderer.cpp @@ -35,10 +35,11 @@ class VulkanRenderer : public Renderer public: bool Init() override { - printf("VulkanRenderer::Init\n"); + DEBUG_LOG(RENDERER, "VulkanRenderer::Init"); shaderManager.Init(); texCommandPool.Init(); + // FIXME this might be called after initial init texAllocator.SetChunkSize(16 * 1024 * 1024); while (textureDrawer.size() < 2) textureDrawer.emplace_back(); @@ -56,16 +57,18 @@ public: { texCommandPool.Init(); screenDrawer.Init(&samplerManager, &shaderManager); + quadPipeline.Init(&shaderManager); } void Term() override { - printf("VulkanRenderer::Term\n"); + DEBUG_LOG(RENDERER, "VulkanRenderer::Term"); GetContext()->WaitIdle(); killtex(); fogTexture = nullptr; texCommandPool.Term(); shaderManager.Term(); + framebufferTextures.clear(); } bool RenderFramebuffer() diff --git a/shell/android-studio/reicast/src/main/jni/Android.mk b/shell/android-studio/reicast/src/main/jni/Android.mk index fd7d982cf..33447ec19 100644 --- a/shell/android-studio/reicast/src/main/jni/Android.mk +++ b/shell/android-studio/reicast/src/main/jni/Android.mk @@ -22,6 +22,7 @@ USE_GLES := 1 CHD5_LZMA := 1 CHD5_FLAC := 1 USE_MODEM := 1 +USE_VULKAN = 1 ifneq ($(TARGET_ARCH_ABI),armeabi-v7a) NOT_ARM := 1 @@ -33,7 +34,6 @@ ifeq ($(TARGET_ARCH_ABI),arm64-v8a) # CPP_REC := 1 ARM64_REC := 1 ISARM64 := 1 - USE_VULKAN = 1 else # CPP_REC := ARM64_REC := @@ -61,7 +61,7 @@ include $(LOCAL_PATH)/../../../../../core/core.mk LOCAL_SRC_FILES := $(RZDCY_FILES) LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/jni/src/Android.cpp) LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/jni/src/utils.cpp) -LOCAL_CFLAGS := $(RZDCY_CFLAGS) -fPIC -fvisibility=hidden -ffunction-sections -fdata-sections -DVK_USE_PLATFORM_ANDROID_KHR +LOCAL_CFLAGS := $(RZDCY_CFLAGS) -fPIC -fvisibility=hidden -ffunction-sections -fdata-sections -DVK_USE_PLATFORM_ANDROID_KHR #-DDEBUGFAST LOCAL_CXXFLAGS := $(RZDCY_CXXFLAGS) -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -fexceptions LOCAL_CPPFLAGS := $(RZDCY_CXXFLAGS) -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections -fexceptions diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index 6d4bd7e85..d7b4f19aa 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -25,6 +25,7 @@ #include "rend/gui.h" #include "cfg/cfg.h" #include "log/LogManager.h" +#include "rend/vulkan/vulkan.h" JavaVM* g_jvm; @@ -402,8 +403,64 @@ extern void egl_stealcntx(); static void *render_thread_func(void *) { +#ifdef USE_VULKAN + VulkanContext *vulkanContext = nullptr; + if (settings.pvr.rend == 4) + { + // Vulkan init + INFO_LOG(RENDERER, "Initializing Vulkan"); + vulkanContext = new VulkanContext(); + std::vector extensions; + extensions.emplace_back("VK_KHR_surface"); + extensions.emplace_back("VK_KHR_android_surface"); + if (vulkanContext->InitInstance(&extensions[0], extensions.size())) + { + VkAndroidSurfaceCreateInfoKHR createInfo { + .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .window = g_window + }; + VkSurfaceKHR surface; + if (vkCreateAndroidSurfaceKHR(vulkanContext->GetInstance(), &createInfo, nullptr, &surface) != VK_SUCCESS) + { + ERROR_LOG(RENDERER, "Vulkan surface creation failed"); + settings.pvr.rend = 0; + + } + else + { + vulkanContext->SetSurface(surface); + if (!vulkanContext->InitDevice()) + settings.pvr.rend = 0; + else + INFO_LOG(RENDERER, "Vulkan init done"); + } + } + else + { + settings.pvr.rend = 0; + } + } + if (settings.pvr.rend != 4) + { + // Clean up any aborted vulkan context in case it failed to initialize + // and fall back to Open GL + if (vulkanContext == nullptr) + { + delete vulkanContext; + vulkanContext = nullptr; + } + INFO_LOG(RENDERER, "Initializing OpenGL"); + } + +#endif rend_thread(NULL); +#ifdef USE_VULKAN + if (vulkanContext) + delete vulkanContext; +#endif ANativeWindow_release(g_window); g_window = NULL; diff --git a/shell/linux/Makefile b/shell/linux/Makefile index 071f57a1a..67b795e60 100644 --- a/shell/linux/Makefile +++ b/shell/linux/Makefile @@ -377,10 +377,6 @@ ifdef HAS_SOFTREND CFLAGS += -msse4.1 endif -ifdef USE_VULKAN - CFLAGS += -D USE_VULKAN -endif - # these are also handled on core.mk, but ignored here # GLES on x11?