vulkan: android support

align uniform buffers according to physical device requirements
destroy old swap chain before creating new one
some drivers don't support some 16-bit texture formats for optimal
tiling
This commit is contained in:
Flyinghead 2019-10-15 16:49:20 +02:00
parent e3a997b642
commit d28a7f45c5
15 changed files with 263 additions and 68 deletions

View File

@ -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 \

View File

@ -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

View File

@ -4,6 +4,7 @@
#include <unordered_map>
#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();

View File

@ -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);

View File

@ -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<float, 5> pushConstants = { 1 - FPU_SHAD_SCALE.scale_factor / 256.f, 0, 0, 0, 0 };
cmdBuffer.pushConstants<float>(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<const void *> chunks;
std::vector<u32> 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<u32>& 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++)

View File

@ -80,8 +80,18 @@ private:
void DrawSorted(const vk::CommandBuffer& cmdBuffer, const std::vector<SortTrigDrawParam>& polys);
void DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, const List<PolyParam>& 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<std::vector<SortTrigDrawParam>> sortedPolys;
std::vector<std::vector<u32>> sortedIndexes;

View File

@ -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<vk::DescriptorBufferInfo> 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<vk::WriteDescriptorSet> 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);

View File

@ -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<BufferData>(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;

View File

@ -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);

View File

@ -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<VkInstance>(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;
};

View File

@ -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<const char *> 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<VkInstance>(*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<vk::QueueFamilyProperties> 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<vk::Image> swapChainImages = device->getSwapchainImagesKHR(*swapChain);
@ -557,19 +626,21 @@ void VulkanContext::Present()
VulkanContext::~VulkanContext()
{
printf("VulkanContext::~VulkanContext\n");
ImGui_ImplVulkan_Shutdown();
std::vector<u8> 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<u8> 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;

View File

@ -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()

View File

@ -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

View File

@ -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<const char*> 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;

View File

@ -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?