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:
parent
e3a997b642
commit
d28a7f45c5
15
core/core.mk
15
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 \
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
Loading…
Reference in New Issue