diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp
index 0b25543c1..d05579328 100644
--- a/core/rend/TexCache.cpp
+++ b/core/rend/TexCache.cpp
@@ -388,7 +388,7 @@ void BaseTextureCacheData::PrintTextureName()
//true if : dirty or paletted texture and hashes don't match
bool BaseTextureCacheData::NeedsUpdate() {
- bool rc = dirty;
+ bool rc = dirty != 0;
if (tex_type != TextureType::_8)
{
if (tcw.PixelFmt == PixelPal4 && palette_hash != pal_hash_16[tcw.PalSelect])
@@ -421,7 +421,6 @@ bool BaseTextureCacheData::Delete()
void BaseTextureCacheData::Create()
{
//Reset state info ..
- Lookups = 0;
Updates = 0;
dirty = FrameCount;
lock_block = nullptr;
diff --git a/core/rend/TexCache.h b/core/rend/TexCache.h
index 4575242cd..c74bf06cd 100644
--- a/core/rend/TexCache.h
+++ b/core/rend/TexCache.h
@@ -651,8 +651,6 @@ public:
// Decoded/filtered texture format
TextureType tex_type;
- u32 Lookups;
-
u32 sa; //pixel data start address in vram (might be offset for mipmaps/etc)
u32 sa_tex; //texture data start address in vram
u32 w,h; //width & height of the texture
@@ -770,7 +768,6 @@ public:
texture->tsp = tsp;
texture->tcw = tcw;
}
- texture->Lookups++;
return texture;
}
diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp
index a8b69d9ae..a3531e917 100644
--- a/core/rend/vulkan/drawer.cpp
+++ b/core/rend/vulkan/drawer.cpp
@@ -471,13 +471,15 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
texture->readOnlyImageView = *texture->imageView;
textureCache->DestroyLater(texture);
}
+ textureCache->SetInFlight(texture);
if (texture->format != vk::Format::eR8G8B8A8Unorm || texture->extent.width != widthPow2 || texture->extent.height != heightPow2)
{
texture->extent = vk::Extent2D(widthPow2, heightPow2);
texture->format = vk::Format::eR8G8B8A8Unorm;
+ texture->needsStaging = true;
texture->CreateImage(vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled,
- vk::ImageLayout::eUndefined, vk::MemoryPropertyFlags(), vk::ImageAspectFlagBits::eColor);
+ vk::ImageLayout::eUndefined, vk::ImageAspectFlagBits::eColor);
colorImageCurrentLayout = vk::ImageLayout::eUndefined;
}
else
diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp
index ecece3674..4b648870a 100644
--- a/core/rend/vulkan/oit/oit_drawer.cpp
+++ b/core/rend/vulkan/oit/oit_drawer.cpp
@@ -540,12 +540,15 @@ vk::CommandBuffer OITTextureDrawer::NewFrame()
texture->readOnlyImageView = *texture->imageView;
textureCache->DestroyLater(texture);
}
+ textureCache->SetInFlight(texture);
+
if (texture->format != vk::Format::eR8G8B8A8Unorm || texture->extent.width != widthPow2 || texture->extent.height != heightPow2)
{
texture->extent = vk::Extent2D(widthPow2, heightPow2);
texture->format = vk::Format::eR8G8B8A8Unorm;
+ texture->needsStaging = true;
texture->CreateImage(vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled,
- vk::ImageLayout::eUndefined, vk::MemoryPropertyFlags(), vk::ImageAspectFlagBits::eColor);
+ vk::ImageLayout::eUndefined, vk::ImageAspectFlagBits::eColor);
colorImageCurrentLayout = vk::ImageLayout::eUndefined;
}
else
diff --git a/core/rend/vulkan/oit/oit_renderer.cpp b/core/rend/vulkan/oit/oit_renderer.cpp
index d875f24ca..fb2745f52 100644
--- a/core/rend/vulkan/oit/oit_renderer.cpp
+++ b/core/rend/vulkan/oit/oit_renderer.cpp
@@ -19,61 +19,27 @@
along with Flycast. If not, see .
*/
#include "../vulkan.h"
-#include "hw/pvr/ta.h"
-#include "hw/pvr/Renderer_if.h"
-#include "../commandpool.h"
+#include "../vulkan_renderer.h"
#include "oit_drawer.h"
#include "oit_shaders.h"
-#include "rend/gui.h"
-#include "rend/osd.h"
-#include "../pipeline.h"
#include "oit_buffer.h"
-#include
-#include
-
-class OITVulkanRenderer : public Renderer
+class OITVulkanRenderer final : public BaseVulkanRenderer
{
public:
bool Init() override
{
DEBUG_LOG(RENDERER, "OITVulkanRenderer::Init");
try {
- texCommandPool.Init();
+ BaseVulkanRenderer::Init();
oitBuffers.Init(0, 0);
- textureDrawer.Init(&samplerManager, &shaderManager, &textureCache, &oitBuffers);
+ textureDrawer.Init(&samplerManager, &oitShaderManager, &textureCache, &oitBuffers);
textureDrawer.SetCommandPool(&texCommandPool);
- screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers);
+ screenDrawer.Init(&samplerManager, &oitShaderManager, &oitBuffers);
screenDrawer.SetCommandPool(&texCommandPool);
-#ifdef __ANDROID__
- if (!vjoyTexture)
- {
- int w, h;
- u8 *image_data = loadOSDButtons(w, h);
- texCommandPool.BeginFrame();
- vjoyTexture = std::unique_ptr(new Texture());
- vjoyTexture->tex_type = TextureType::_8888;
- vjoyTexture->tcw.full = 0;
- vjoyTexture->tsp.full = 0;
- vjoyTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- vjoyTexture->SetDevice(GetContext()->GetDevice());
- vjoyTexture->SetCommandBuffer(texCommandPool.Allocate());
- vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data, false);
- vjoyTexture->SetCommandBuffer(nullptr);
- texCommandPool.EndFrame();
- delete [] image_data;
- osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
- }
- if (!osdBuffer)
- {
- osdBuffer = std::unique_ptr(new BufferData(sizeof(OSDVertex) * VJOY_VISIBLE * 4,
- vk::BufferUsageFlagBits::eVertexBuffer));
- }
-#endif
-
return true;
}
catch (const vk::SystemError& err)
@@ -86,11 +52,8 @@ public:
void Resize(int w, int h) override
{
NOTICE_LOG(RENDERER, "OIT Resize %d x %d", w, h);
- texCommandPool.Init();
- screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers);
-#ifdef __ANDROID__
- osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
-#endif
+ BaseVulkanRenderer::Resize(w, h);
+ screenDrawer.Init(&samplerManager, &oitShaderManager, &oitBuffers);
}
void Term() override
@@ -100,114 +63,7 @@ public:
screenDrawer.Term();
textureDrawer.Term();
oitBuffers.Term();
- osdBuffer.reset();
- textureCache.Clear();
- fogTexture = nullptr;
- texCommandPool.Term();
- framebufferTextures.clear();
- }
-
- bool RenderFramebuffer()
- {
- if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
- return false;
-
- PixelBuffer pb;
- int width;
- int height;
- ReadFramebuffer(pb, width, height);
-
- if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
- framebufferTextures.resize(GetContext()->GetSwapChainSize());
- std::unique_ptr& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
- if (!curTexture)
- {
- curTexture = std::unique_ptr(new Texture());
- curTexture->tex_type = TextureType::_8888;
- curTexture->tcw.full = 0;
- curTexture->tsp.full = 0;
- curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- curTexture->SetDevice(GetContext()->GetDevice());
- }
- curTexture->SetCommandBuffer(texCommandPool.Allocate());
- curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
- curTexture->SetCommandBuffer(nullptr);
- texCommandPool.EndFrame();
-
- GetContext()->PresentFrame(curTexture->GetImageView(), { 640, 480 });
-
- return true;
- }
-
- bool Process(TA_context* ctx) override
- {
- texCommandPool.BeginFrame();
- textureCache.SetCurrentIndex(texCommandPool.GetIndex());
-
- if (ctx->rend.isRenderFramebuffer)
- {
- return RenderFramebuffer();
- }
-
- ctx->rend_inuse.lock();
-
- if (KillTex)
- textureCache.Clear();
-
- bool result = ta_parse_vdrc(ctx);
-
- textureCache.CollectCleanup();
-
- if (result)
- {
- CheckFogTexture();
- CheckPaletteTexture();
- }
- else
- texCommandPool.EndFrame();
-
- return result;
- }
-
- void DrawOSD(bool clear_screen) override
- {
- gui_display_osd();
- if (!vjoyTexture)
- return;
- if (clear_screen)
- {
- GetContext()->NewFrame();
- GetContext()->BeginRenderPass();
- }
- const float dc2s_scale_h = screen_height / 480.0f;
- const float sidebarWidth = (screen_width - dc2s_scale_h * 640.0f) / 2;
-
- std::vector osdVertices = GetOSDVertices();
- const float x1 = 2.0f / (screen_width / dc2s_scale_h);
- const float y1 = 2.0f / 480;
- const float x2 = 1 - 2 * sidebarWidth / screen_width;
- const float y2 = 1;
- for (OSDVertex& vtx : osdVertices)
- {
- vtx.x = vtx.x * x1 - x2;
- vtx.y = vtx.y * y1 - y2;
- }
-
- const vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer();
- cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, osdPipeline.GetPipeline());
-
- osdPipeline.BindDescriptorSets(cmdBuffer);
- const vk::Viewport viewport(0, 0, (float)screen_width, (float)screen_height, 0, 1.f);
- cmdBuffer.setViewport(0, 1, &viewport);
- const vk::Rect2D scissor({ 0, 0 }, { (u32)screen_width, (u32)screen_height });
- cmdBuffer.setScissor(0, 1, &scissor);
- osdBuffer->upload(osdVertices.size() * sizeof(OSDVertex), osdVertices.data());
- const vk::DeviceSize zero = 0;
- cmdBuffer.bindVertexBuffers(0, 1, &osdBuffer->buffer.get(), &zero);
- for (size_t i = 0; i < osdVertices.size(); i += 4)
- cmdBuffer.draw(4, 1, i, 0);
- if (clear_screen)
- GetContext()->EndFrame();
+ BaseVulkanRenderer::Term();
}
bool Render() override
@@ -228,100 +84,12 @@ public:
return !pvrrc.isRTT;
}
- void Present() override
- {
- GetContext()->Present();
- }
-
- virtual u64 GetTexture(TSP tsp, TCW tcw) override
- {
- Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
-
- if (tf->IsNew())
- {
- tf->Create();
- tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- tf->SetDevice(GetContext()->GetDevice());
- }
-
- //update if needed
- if (tf->NeedsUpdate())
- {
- textureCache.DestroyLater(tf);
- tf->SetCommandBuffer(texCommandPool.Allocate());
- tf->Update();
- }
- else if (tf->IsCustomTextureAvailable())
- {
- textureCache.DestroyLater(tf);
- tf->SetCommandBuffer(texCommandPool.Allocate());
- tf->CheckCustomTexture();
- }
- tf->SetCommandBuffer(nullptr);
-
- return tf->GetIntId();
- }
-
private:
- VulkanContext *GetContext() const { return VulkanContext::Instance(); }
-
- void CheckFogTexture()
- {
- if (!fogTexture)
- {
- fogTexture = std::unique_ptr(new Texture());
- fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- fogTexture->SetDevice(GetContext()->GetDevice());
- fogTexture->tex_type = TextureType::_8;
- fog_needs_update = true;
- }
- if (!fog_needs_update || !settings.rend.Fog)
- return;
- fog_needs_update = false;
- u8 texData[256];
- MakeFogTexture(texData);
- fogTexture->SetCommandBuffer(texCommandPool.Allocate());
-
- fogTexture->UploadToGPU(128, 2, texData, false);
-
- fogTexture->SetCommandBuffer(nullptr);
- }
- void CheckPaletteTexture()
- {
- if (!paletteTexture)
- {
- paletteTexture = std::unique_ptr(new Texture());
- paletteTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- paletteTexture->SetDevice(GetContext()->GetDevice());
- paletteTexture->tex_type = TextureType::_8888;
- palette_updated = true;
- }
- if (!palette_updated)
- return;
- palette_updated = false;
-
- paletteTexture->SetCommandBuffer(texCommandPool.Allocate());
-
- paletteTexture->UploadToGPU(1024, 1, (u8 *)palette32_ram, false);
-
- paletteTexture->SetCommandBuffer(nullptr);
- }
-
OITBuffers oitBuffers;
- std::unique_ptr fogTexture;
- std::unique_ptr paletteTexture;
- CommandPool texCommandPool;
-
SamplerManager samplerManager;
- OITShaderManager shaderManager;
- ShaderManager normalShaderManager;
+ OITShaderManager oitShaderManager;
OITScreenDrawer screenDrawer;
OITTextureDrawer textureDrawer;
- std::vector> framebufferTextures;
- OSDPipeline osdPipeline;
- std::unique_ptr vjoyTexture;
- std::unique_ptr osdBuffer;
- TextureCache textureCache;
};
Renderer* rend_OITVulkan()
diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp
index 432c90f53..d6d60876f 100644
--- a/core/rend/vulkan/texture.cpp
+++ b/core/rend/vulkan/texture.cpp
@@ -202,37 +202,39 @@ void Texture::Init(u32 width, u32 height, vk::Format format, u32 dataSize, bool
== vk::FormatFeatureFlagBits::eSampledImage
? vk::ImageTiling::eOptimal
: vk::ImageTiling::eLinear;
+ if (height <= 32
+ && dataSize / height <= 64
+ && !mipmapped
+ && (formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) == vk::FormatFeatureFlagBits::eSampledImage)
+ imageTiling = vk::ImageTiling::eLinear;
needsStaging = imageTiling != vk::ImageTiling::eLinear;
vk::ImageLayout initialLayout;
- vk::MemoryPropertyFlags requirements;
vk::ImageUsageFlags usageFlags = vk::ImageUsageFlagBits::eSampled;
if (needsStaging)
{
stagingBufferData = std::unique_ptr(new BufferData(dataSize, vk::BufferUsageFlagBits::eTransferSrc));
usageFlags |= vk::ImageUsageFlagBits::eTransferDst;
initialLayout = vk::ImageLayout::eUndefined;
- requirements = vk::MemoryPropertyFlagBits::eDeviceLocal;
}
else
{
verify((formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eSampledImage) == vk::FormatFeatureFlagBits::eSampledImage);
initialLayout = vk::ImageLayout::ePreinitialized;
- requirements = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
}
if (mipmapped && !mipmapsIncluded)
usageFlags |= vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
- CreateImage(imageTiling, usageFlags, initialLayout, requirements, vk::ImageAspectFlagBits::eColor);
+ CreateImage(imageTiling, usageFlags, initialLayout, vk::ImageAspectFlagBits::eColor);
}
void Texture::CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout,
- vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask)
+ vk::ImageAspectFlags aspectMask)
{
vk::ImageCreateInfo imageCreateInfo(vk::ImageCreateFlags(), vk::ImageType::e2D, format, vk::Extent3D(extent, 1), mipmapLevels, 1,
vk::SampleCountFlagBits::e1, tiling, usage,
vk::SharingMode::eExclusive, 0, nullptr, initialLayout);
image = device.createImageUnique(imageCreateInfo);
- VmaAllocationCreateInfo allocCreateInfo = { VmaAllocationCreateFlags(), VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_ONLY };
+ VmaAllocationCreateInfo allocCreateInfo = { VmaAllocationCreateFlags(), needsStaging ? VmaMemoryUsage::VMA_MEMORY_USAGE_GPU_ONLY : VmaMemoryUsage::VMA_MEMORY_USAGE_CPU_TO_GPU };
if (!needsStaging)
allocCreateInfo.flags = VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT;
allocation = VulkanContext::Instance()->GetAllocator().AllocateForImage(*image, allocCreateInfo);
@@ -247,8 +249,8 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
verify((bool)commandBuffer);
commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
-// if (!isNew && !needsStaging)
-// setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eUndefined);
+ if (!isNew && !needsStaging)
+ setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eGeneral);
void* data;
if (needsStaging)
@@ -270,6 +272,25 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
src += size;
}
}
+ else if (!needsStaging)
+ {
+ vk::SubresourceLayout layout = device.getImageSubresourceLayout(*image, vk::ImageSubresource(vk::ImageAspectFlagBits::eColor, 0, 0));
+ if (layout.size != srcSize)
+ {
+ u8 *src = (u8 *)srcData;
+ u8 *dst = (u8 *)data;
+ u32 srcSz = extent.width * 2;
+ if (tex_type == TextureType::_8888)
+ srcSz *= 2;
+ else if (tex_type == TextureType::_8)
+ srcSz /= 2;
+ u8 * const srcEnd = src + srcSz * extent.height;
+ for (; src < srcEnd; src += srcSz, dst += layout.rowPitch)
+ memcpy(dst, src, srcSz);
+ }
+ else
+ memcpy(data, srcData, srcSize);
+ }
else
memcpy(data, srcData, srcSize);
@@ -309,7 +330,8 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew, bool genMipmaps)
GenerateMipmaps();
else
// If we can use the linear tiled image as a texture, just do it
- setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal);
+ setImageLayout(commandBuffer, image.get(), format, mipmapLevels, isNew ? vk::ImageLayout::ePreinitialized : vk::ImageLayout::eGeneral,
+ vk::ImageLayout::eShaderReadOnlyOptimal);
}
commandBuffer.end();
}
diff --git a/core/rend/vulkan/texture.h b/core/rend/vulkan/texture.h
index 8927857d4..692023661 100644
--- a/core/rend/vulkan/texture.h
+++ b/core/rend/vulkan/texture.h
@@ -52,7 +52,7 @@ private:
void Init(u32 width, u32 height, vk::Format format ,u32 dataSize, bool mipmapped, bool mipmapsIncluded);
void SetImage(u32 size, void *data, bool isNew, bool genMipmaps);
void CreateImage(vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::ImageLayout initialLayout,
- vk::MemoryPropertyFlags memoryProperties, vk::ImageAspectFlags aspectMask);
+ vk::ImageAspectFlags aspectMask);
void GenerateMipmaps();
vk::Format format = vk::Format::eUndefined;
@@ -137,13 +137,6 @@ private:
class TextureCache : public BaseTextureCache
{
public:
- Texture *getTextureCacheData(TSP tsp, TCW tcw)
- {
- Texture *texture = BaseTextureCache::getTextureCacheData(tsp, tcw);
- inFlightTextures[currentIndex].insert(texture);
- return texture;
- }
-
void SetCurrentIndex(int index) {
if (currentIndex < inFlightTextures.size())
std::for_each(inFlightTextures[currentIndex].begin(), inFlightTextures[currentIndex].end(),
@@ -158,8 +151,15 @@ public:
bool IsInFlight(Texture *texture)
{
- return std::any_of(inFlightTextures.begin(), inFlightTextures.end(),
- [texture](const std::unordered_set& set) { return set.find(texture) != set.end(); });
+ for (u32 i = 0; i < inFlightTextures.size(); i++)
+ if (i != currentIndex && inFlightTextures[i].find(texture) != inFlightTextures[i].end())
+ return true;
+ return false;
+ }
+
+ void SetInFlight(Texture *texture)
+ {
+ inFlightTextures[currentIndex].insert(texture);
}
void DestroyLater(Texture *texture)
diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp
index 15eaacef7..312df48c9 100644
--- a/core/rend/vulkan/vulkan_context.cpp
+++ b/core/rend/vulkan/vulkan_context.cpp
@@ -97,6 +97,9 @@ VKAPI_ATTR static VkBool32 VKAPI_CALL debugUtilsMessengerCallback(VkDebugUtilsMe
return VK_TRUE;
}
#else
+#if HOST_CPU == CPU_ARM
+__attribute__((pcs("aapcs-vfp")))
+#endif
static VkBool32 debugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode,
const char* pLayerPrefix, const char* pMessage, void* /*pUserData*/)
{
@@ -563,7 +566,7 @@ void VulkanContext::CreateSwapChain()
(surfaceCapabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::ePreMultiplied) ? vk::CompositeAlphaFlagBitsKHR::ePreMultiplied :
(surfaceCapabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::ePostMultiplied) ? vk::CompositeAlphaFlagBitsKHR::ePostMultiplied :
(surfaceCapabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eInherit) ? vk::CompositeAlphaFlagBitsKHR::eInherit : vk::CompositeAlphaFlagBitsKHR::eOpaque;
- u32 imageCount = std::max(3u, surfaceCapabilities.minImageCount);
+ u32 imageCount = std::max(2u, surfaceCapabilities.minImageCount);
if (surfaceCapabilities.maxImageCount != 0)
imageCount = std::min(imageCount, surfaceCapabilities.maxImageCount);
vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eColorAttachment;
@@ -818,6 +821,7 @@ void VulkanContext::PresentLastFrame()
void VulkanContext::Term()
{
lastFrameView = nullptr;
+ device->waitIdle();
ImGui_ImplVulkan_Shutdown();
gui_term();
if (device && pipelineCache)
diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp
index d022f49d4..8cb10662b 100644
--- a/core/rend/vulkan/vulkan_renderer.cpp
+++ b/core/rend/vulkan/vulkan_renderer.cpp
@@ -19,23 +19,17 @@
along with Flycast. If not, see .
*/
#include "vulkan.h"
-#include "hw/pvr/Renderer_if.h"
-#include "hw/pvr/ta.h"
-#include "commandpool.h"
+#include "vulkan_renderer.h"
#include "drawer.h"
#include "shaders.h"
-#include "rend/gui.h"
-#include "rend/osd.h"
-#include
-
-class VulkanRenderer : public Renderer
+class VulkanRenderer final : public BaseVulkanRenderer
{
public:
bool Init() override
{
DEBUG_LOG(RENDERER, "VulkanRenderer::Init");
- texCommandPool.Init();
+ BaseVulkanRenderer::Init();
textureDrawer.Init(&samplerManager, &shaderManager, &textureCache);
textureDrawer.SetCommandPool(&texCommandPool);
@@ -43,158 +37,20 @@ public:
screenDrawer.Init(&samplerManager, &shaderManager);
screenDrawer.SetCommandPool(&texCommandPool);
-#ifdef __ANDROID__
- if (!vjoyTexture)
- {
- int w, h;
- u8 *image_data = loadOSDButtons(w, h);
- texCommandPool.BeginFrame();
- vjoyTexture = std::unique_ptr(new Texture());
- vjoyTexture->tex_type = TextureType::_8888;
- vjoyTexture->tcw.full = 0;
- vjoyTexture->tsp.full = 0;
- vjoyTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- vjoyTexture->SetDevice(GetContext()->GetDevice());
- vjoyTexture->SetCommandBuffer(texCommandPool.Allocate());
- vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data, false);
- vjoyTexture->SetCommandBuffer(nullptr);
- texCommandPool.EndFrame();
- delete [] image_data;
- osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
- }
- if (!osdBuffer)
- {
- osdBuffer = std::unique_ptr(new BufferData(sizeof(OSDVertex) * VJOY_VISIBLE * 4,
- vk::BufferUsageFlagBits::eVertexBuffer));
- }
-#endif
-
return true;
}
void Resize(int w, int h) override
{
- texCommandPool.Init();
+ BaseVulkanRenderer::Resize(w, h);
screenDrawer.Init(&samplerManager, &shaderManager);
-#ifdef __ANDROID__
- osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
-#endif
}
void Term() override
{
DEBUG_LOG(RENDERER, "VulkanRenderer::Term");
GetContext()->WaitIdle();
- osdBuffer.reset();
- vjoyTexture.reset();
- textureCache.Clear();
- fogTexture = nullptr;
- texCommandPool.Term();
- framebufferTextures.clear();
- }
-
- bool RenderFramebuffer()
- {
- if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
- return false;
-
- PixelBuffer pb;
- int width;
- int height;
- ReadFramebuffer(pb, width, height);
-
- if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
- framebufferTextures.resize(GetContext()->GetSwapChainSize());
- std::unique_ptr& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
- if (!curTexture)
- {
- curTexture = std::unique_ptr(new Texture());
- curTexture->tex_type = TextureType::_8888;
- curTexture->tcw.full = 0;
- curTexture->tsp.full = 0;
- curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- curTexture->SetDevice(GetContext()->GetDevice());
- }
- curTexture->SetCommandBuffer(texCommandPool.Allocate());
- curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
- curTexture->SetCommandBuffer(nullptr);
- texCommandPool.EndFrame();
-
- GetContext()->PresentFrame(curTexture->GetImageView(), { 640, 480 });
-
- return true;
- }
-
- bool Process(TA_context* ctx) override
- {
- texCommandPool.BeginFrame();
- textureCache.SetCurrentIndex(texCommandPool.GetIndex());
-
- if (ctx->rend.isRenderFramebuffer)
- {
- return RenderFramebuffer();
- }
-
- ctx->rend_inuse.lock();
-
- if (KillTex)
- textureCache.Clear();
-
- bool result = ta_parse_vdrc(ctx);
-
- textureCache.CollectCleanup();
-
- if (result)
- {
- CheckFogTexture();
- CheckPaletteTexture();
- }
- else
- texCommandPool.EndFrame();
-
- return result;
- }
-
- // FIXME This needs to go in its own class
- void DrawOSD(bool clear_screen) override
- {
- gui_display_osd();
- if (!vjoyTexture)
- return;
- if (clear_screen)
- {
- GetContext()->NewFrame();
- GetContext()->BeginRenderPass();
- }
- const float dc2s_scale_h = screen_height / 480.0f;
- const float sidebarWidth = (screen_width - dc2s_scale_h * 640.0f) / 2;
-
- std::vector osdVertices = GetOSDVertices();
- const float x1 = 2.0f / (screen_width / dc2s_scale_h);
- const float y1 = 2.0f / 480;
- const float x2 = 1 - 2 * sidebarWidth / screen_width;
- const float y2 = 1;
- for (OSDVertex& vtx : osdVertices)
- {
- vtx.x = vtx.x * x1 - x2;
- vtx.y = vtx.y * y1 - y2;
- }
-
- const vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer();
- cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, osdPipeline.GetPipeline());
-
- osdPipeline.BindDescriptorSets(cmdBuffer);
- const vk::Viewport viewport(0, 0, (float)screen_width, (float)screen_height, 0, 1.f);
- cmdBuffer.setViewport(0, 1, &viewport);
- const vk::Rect2D scissor({ 0, 0 }, { (u32)screen_width, (u32)screen_height });
- cmdBuffer.setScissor(0, 1, &scissor);
- osdBuffer->upload(osdVertices.size() * sizeof(OSDVertex), osdVertices.data());
- const vk::DeviceSize zero = 0;
- cmdBuffer.bindVertexBuffers(0, 1, &osdBuffer->buffer.get(), &zero);
- for (size_t i = 0; i < osdVertices.size(); i += 4)
- cmdBuffer.draw(4, 1, i, 0);
- if (clear_screen)
- GetContext()->EndFrame();
+ BaseVulkanRenderer::Term();
}
bool Render() override
@@ -215,98 +71,10 @@ public:
return !pvrrc.isRTT;
}
- void Present() override
- {
- GetContext()->Present();
- }
-
- virtual u64 GetTexture(TSP tsp, TCW tcw) override
- {
- Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
-
- if (tf->IsNew())
- {
- tf->Create();
- tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- tf->SetDevice(GetContext()->GetDevice());
- }
-
- //update if needed
- if (tf->NeedsUpdate())
- {
- textureCache.DestroyLater(tf);
- tf->SetCommandBuffer(texCommandPool.Allocate());
- tf->Update();
- }
- else if (tf->IsCustomTextureAvailable())
- {
- textureCache.DestroyLater(tf);
- tf->SetCommandBuffer(texCommandPool.Allocate());
- tf->CheckCustomTexture();
- }
- tf->SetCommandBuffer(nullptr);
-
- return tf->GetIntId();
- }
-
private:
- VulkanContext *GetContext() const { return VulkanContext::Instance(); }
-
- void CheckFogTexture()
- {
- if (!fogTexture)
- {
- fogTexture = std::unique_ptr(new Texture());
- fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- fogTexture->SetDevice(GetContext()->GetDevice());
- fogTexture->tex_type = TextureType::_8;
- fog_needs_update = true;
- }
- if (!fog_needs_update || !settings.rend.Fog)
- return;
- fog_needs_update = false;
- u8 texData[256];
- MakeFogTexture(texData);
- fogTexture->SetCommandBuffer(texCommandPool.Allocate());
-
- fogTexture->UploadToGPU(128, 2, texData, false);
-
- fogTexture->SetCommandBuffer(nullptr);
- }
- void CheckPaletteTexture()
- {
- if (!paletteTexture)
- {
- paletteTexture = std::unique_ptr(new Texture());
- paletteTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
- paletteTexture->SetDevice(GetContext()->GetDevice());
- paletteTexture->tex_type = TextureType::_8888;
- palette_updated = true;
- }
- if (!palette_updated)
- return;
- palette_updated = false;
-
- paletteTexture->SetCommandBuffer(texCommandPool.Allocate());
-
- paletteTexture->UploadToGPU(1024, 1, (u8 *)palette32_ram, false);
-
- paletteTexture->SetCommandBuffer(nullptr);
- }
-
- std::unique_ptr fogTexture;
- std::unique_ptr paletteTexture;
- CommandPool texCommandPool;
-
SamplerManager samplerManager;
- ShaderManager shaderManager;
ScreenDrawer screenDrawer;
TextureDrawer textureDrawer;
- std::vector> framebufferTextures;
- OSDPipeline osdPipeline;
- std::unique_ptr vjoyTexture;
- std::unique_ptr osdBuffer;
- TextureCache textureCache;
};
Renderer* rend_Vulkan()
diff --git a/core/rend/vulkan/vulkan_renderer.h b/core/rend/vulkan/vulkan_renderer.h
new file mode 100644
index 000000000..413573835
--- /dev/null
+++ b/core/rend/vulkan/vulkan_renderer.h
@@ -0,0 +1,279 @@
+/*
+ Copyright 2020 flyinghead
+
+ This file is part of Flycast.
+
+ Flycast is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ Flycast is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Flycast. If not, see .
+*/
+#include "vulkan.h"
+#include "hw/pvr/Renderer_if.h"
+#include "hw/pvr/ta.h"
+#include "commandpool.h"
+#include "pipeline.h"
+#include "rend/gui.h"
+#include "rend/osd.h"
+
+#include
+#include
+
+class BaseVulkanRenderer : public Renderer
+{
+public:
+ virtual bool Init() override
+ {
+ texCommandPool.Init();
+
+#ifdef __ANDROID__
+ if (!vjoyTexture)
+ {
+ int w, h;
+ u8 *image_data = loadOSDButtons(w, h);
+ texCommandPool.BeginFrame();
+ vjoyTexture = std::unique_ptr(new Texture());
+ vjoyTexture->tex_type = TextureType::_8888;
+ vjoyTexture->tcw.full = 0;
+ vjoyTexture->tsp.full = 0;
+ vjoyTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
+ vjoyTexture->SetDevice(GetContext()->GetDevice());
+ vjoyTexture->SetCommandBuffer(texCommandPool.Allocate());
+ vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data, false);
+ vjoyTexture->SetCommandBuffer(nullptr);
+ texCommandPool.EndFrame();
+ delete [] image_data;
+ osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
+ }
+ if (!osdBuffer)
+ {
+ osdBuffer = std::unique_ptr(new BufferData(sizeof(OSDVertex) * VJOY_VISIBLE * 4,
+ vk::BufferUsageFlagBits::eVertexBuffer));
+ }
+#endif
+
+ return true;
+ }
+
+ virtual void Term() override
+ {
+ osdBuffer.reset();
+ vjoyTexture.reset();
+ textureCache.Clear();
+ fogTexture = nullptr;
+ paletteTexture = nullptr;
+ texCommandPool.Term();
+ framebufferTextures.clear();
+ }
+
+ virtual u64 GetTexture(TSP tsp, TCW tcw) override
+ {
+ Texture* tf = textureCache.getTextureCacheData(tsp, tcw);
+
+ if (tf->IsNew())
+ {
+ tf->Create();
+ tf->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
+ tf->SetDevice(GetContext()->GetDevice());
+ }
+
+ //update if needed
+ if (tf->NeedsUpdate())
+ {
+ // This kills performance when a frame is skipped and lots of texture updated each frame
+ //if (textureCache.IsInFlight(tf))
+ // textureCache.DestroyLater(tf);
+ tf->SetCommandBuffer(texCommandPool.Allocate());
+ tf->Update();
+ }
+ else if (tf->IsCustomTextureAvailable())
+ {
+ textureCache.DestroyLater(tf);
+ tf->SetCommandBuffer(texCommandPool.Allocate());
+ tf->CheckCustomTexture();
+ }
+ tf->SetCommandBuffer(nullptr);
+ textureCache.SetInFlight(tf);
+
+ return tf->GetIntId();
+ }
+
+ virtual bool Process(TA_context* ctx) override
+ {
+ texCommandPool.BeginFrame();
+ textureCache.SetCurrentIndex(texCommandPool.GetIndex());
+
+ if (ctx->rend.isRenderFramebuffer)
+ return RenderFramebuffer();
+
+ ctx->rend_inuse.lock();
+
+ if (KillTex)
+ textureCache.Clear();
+
+ bool result = ta_parse_vdrc(ctx);
+
+ textureCache.CollectCleanup();
+
+ if (result)
+ {
+ CheckFogTexture();
+ CheckPaletteTexture();
+ }
+ else
+ texCommandPool.EndFrame();
+
+ return result;
+ }
+
+ void Present() override
+ {
+ GetContext()->Present();
+ }
+
+ void Resize(int w, int h) override
+ {
+ texCommandPool.Init();
+#ifdef __ANDROID__
+ osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass());
+#endif
+ }
+
+ void DrawOSD(bool clear_screen) override
+ {
+ gui_display_osd();
+ if (!vjoyTexture)
+ return;
+ if (clear_screen)
+ {
+ GetContext()->NewFrame();
+ GetContext()->BeginRenderPass();
+ }
+ const float dc2s_scale_h = screen_height / 480.0f;
+ const float sidebarWidth = (screen_width - dc2s_scale_h * 640.0f) / 2;
+
+ std::vector osdVertices = GetOSDVertices();
+ const float x1 = 2.0f / (screen_width / dc2s_scale_h);
+ const float y1 = 2.0f / 480;
+ const float x2 = 1 - 2 * sidebarWidth / screen_width;
+ const float y2 = 1;
+ for (OSDVertex& vtx : osdVertices)
+ {
+ vtx.x = vtx.x * x1 - x2;
+ vtx.y = vtx.y * y1 - y2;
+ }
+
+ const vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer();
+ cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, osdPipeline.GetPipeline());
+
+ osdPipeline.BindDescriptorSets(cmdBuffer);
+ const vk::Viewport viewport(0, 0, (float)screen_width, (float)screen_height, 0, 1.f);
+ cmdBuffer.setViewport(0, 1, &viewport);
+ const vk::Rect2D scissor({ 0, 0 }, { (u32)screen_width, (u32)screen_height });
+ cmdBuffer.setScissor(0, 1, &scissor);
+ osdBuffer->upload(osdVertices.size() * sizeof(OSDVertex), osdVertices.data());
+ const vk::DeviceSize zero = 0;
+ cmdBuffer.bindVertexBuffers(0, 1, &osdBuffer->buffer.get(), &zero);
+ for (size_t i = 0; i < osdVertices.size(); i += 4)
+ cmdBuffer.draw(4, 1, i, 0);
+ if (clear_screen)
+ GetContext()->EndFrame();
+ }
+
+protected:
+ VulkanContext *GetContext() const { return VulkanContext::Instance(); }
+
+ bool RenderFramebuffer()
+ {
+ if (FB_R_SIZE.fb_x_size == 0 || FB_R_SIZE.fb_y_size == 0)
+ return false;
+
+ PixelBuffer pb;
+ int width;
+ int height;
+ ReadFramebuffer(pb, width, height);
+
+ if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
+ framebufferTextures.resize(GetContext()->GetSwapChainSize());
+ std::unique_ptr& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
+ if (!curTexture)
+ {
+ curTexture = std::unique_ptr(new Texture());
+ curTexture->tex_type = TextureType::_8888;
+ curTexture->tcw.full = 0;
+ curTexture->tsp.full = 0;
+ curTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
+ curTexture->SetDevice(GetContext()->GetDevice());
+ }
+ curTexture->SetCommandBuffer(texCommandPool.Allocate());
+ curTexture->UploadToGPU(width, height, (u8*)pb.data(), false);
+ curTexture->SetCommandBuffer(nullptr);
+ texCommandPool.EndFrame();
+
+ GetContext()->PresentFrame(curTexture->GetImageView(), { 640, 480 });
+
+ return true;
+ }
+
+ void CheckFogTexture()
+ {
+ if (!fogTexture)
+ {
+ fogTexture = std::unique_ptr(new Texture());
+ fogTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
+ fogTexture->SetDevice(GetContext()->GetDevice());
+ fogTexture->tex_type = TextureType::_8;
+ fog_needs_update = true;
+ }
+ if (!fog_needs_update || !settings.rend.Fog)
+ return;
+ fog_needs_update = false;
+ u8 texData[256];
+ MakeFogTexture(texData);
+ fogTexture->SetCommandBuffer(texCommandPool.Allocate());
+
+ fogTexture->UploadToGPU(128, 2, texData, false);
+
+ fogTexture->SetCommandBuffer(nullptr);
+ }
+
+ void CheckPaletteTexture()
+ {
+ if (!paletteTexture)
+ {
+ paletteTexture = std::unique_ptr(new Texture());
+ paletteTexture->SetPhysicalDevice(GetContext()->GetPhysicalDevice());
+ paletteTexture->SetDevice(GetContext()->GetDevice());
+ paletteTexture->tex_type = TextureType::_8888;
+ palette_updated = true;
+ }
+ if (!palette_updated)
+ return;
+ palette_updated = false;
+
+ paletteTexture->SetCommandBuffer(texCommandPool.Allocate());
+
+ paletteTexture->UploadToGPU(1024, 1, (u8 *)palette32_ram, false);
+
+ paletteTexture->SetCommandBuffer(nullptr);
+ }
+
+ ShaderManager shaderManager;
+ std::unique_ptr fogTexture;
+ std::unique_ptr paletteTexture;
+ CommandPool texCommandPool;
+ std::vector> framebufferTextures;
+ OSDPipeline osdPipeline;
+ std::unique_ptr vjoyTexture;
+ std::unique_ptr osdBuffer;
+ TextureCache textureCache;
+};
+