vulkan: linear tiling for small texs. don't track in-flight texs
Linear tiling is faster for small, frequently updated textures When lots of textures are updated each frame, a skipped frame will destroy/recreate all textures, causing another skipped frame, etc. So in-flight texture tracking is disabled, except for RTT textures Limit swap chain to 2 images Refactor base and oit renderers to avoid code dup
This commit is contained in:
parent
a1dd76818e
commit
1713124711
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -19,61 +19,27 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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 <memory>
|
||||
#include <vector>
|
||||
|
||||
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<Texture>(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<BufferData>(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<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(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<OSDVertex> 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<Texture>(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<Texture>(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<Texture> fogTexture;
|
||||
std::unique_ptr<Texture> paletteTexture;
|
||||
CommandPool texCommandPool;
|
||||
|
||||
SamplerManager samplerManager;
|
||||
OITShaderManager shaderManager;
|
||||
ShaderManager normalShaderManager;
|
||||
OITShaderManager oitShaderManager;
|
||||
OITScreenDrawer screenDrawer;
|
||||
OITTextureDrawer textureDrawer;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
OSDPipeline osdPipeline;
|
||||
std::unique_ptr<Texture> vjoyTexture;
|
||||
std::unique_ptr<BufferData> osdBuffer;
|
||||
TextureCache textureCache;
|
||||
};
|
||||
|
||||
Renderer* rend_OITVulkan()
|
||||
|
|
|
@ -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<BufferData>(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();
|
||||
}
|
||||
|
|
|
@ -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<Texture>
|
||||
{
|
||||
public:
|
||||
Texture *getTextureCacheData(TSP tsp, TCW tcw)
|
||||
{
|
||||
Texture *texture = BaseTextureCache<Texture>::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<Texture *>& 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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -19,23 +19,17 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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 <memory>
|
||||
|
||||
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<Texture>(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<BufferData>(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<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(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<OSDVertex> 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<Texture>(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<Texture>(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<Texture> fogTexture;
|
||||
std::unique_ptr<Texture> paletteTexture;
|
||||
CommandPool texCommandPool;
|
||||
|
||||
SamplerManager samplerManager;
|
||||
ShaderManager shaderManager;
|
||||
ScreenDrawer screenDrawer;
|
||||
TextureDrawer textureDrawer;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
OSDPipeline osdPipeline;
|
||||
std::unique_ptr<Texture> vjoyTexture;
|
||||
std::unique_ptr<BufferData> osdBuffer;
|
||||
TextureCache textureCache;
|
||||
};
|
||||
|
||||
Renderer* rend_Vulkan()
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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 <memory>
|
||||
#include <vector>
|
||||
|
||||
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<Texture>(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<BufferData>(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<OSDVertex> 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<u32> pb;
|
||||
int width;
|
||||
int height;
|
||||
ReadFramebuffer(pb, width, height);
|
||||
|
||||
if (framebufferTextures.size() != GetContext()->GetSwapChainSize())
|
||||
framebufferTextures.resize(GetContext()->GetSwapChainSize());
|
||||
std::unique_ptr<Texture>& curTexture = framebufferTextures[GetContext()->GetCurrentImageIndex()];
|
||||
if (!curTexture)
|
||||
{
|
||||
curTexture = std::unique_ptr<Texture>(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<Texture>(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<Texture>(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<Texture> fogTexture;
|
||||
std::unique_ptr<Texture> paletteTexture;
|
||||
CommandPool texCommandPool;
|
||||
std::vector<std::unique_ptr<Texture>> framebufferTextures;
|
||||
OSDPipeline osdPipeline;
|
||||
std::unique_ptr<Texture> vjoyTexture;
|
||||
std::unique_ptr<BufferData> osdBuffer;
|
||||
TextureCache textureCache;
|
||||
};
|
||||
|
Loading…
Reference in New Issue