From 65e23bb9f350eefdc489ef14b08e8daa8074fa32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 30 Oct 2017 12:05:08 +0100 Subject: [PATCH] Some reorganization. Start implementing framebuffer depal for Vulkan. --- GPU/Common/DepalettizeShaderCommon.h | 2 + GPU/D3D11/DepalettizeShaderD3D11.cpp | 2 - GPU/GLES/DepalettizeShaderGLES.cpp | 2 - GPU/Vulkan/DepalettizeShaderVulkan.cpp | 113 ++++++++++++++++++++++--- GPU/Vulkan/DepalettizeShaderVulkan.h | 39 ++++++--- GPU/Vulkan/FramebufferVulkan.cpp | 95 ++++++--------------- GPU/Vulkan/FramebufferVulkan.h | 26 +++--- GPU/Vulkan/GPU_Vulkan.cpp | 53 +++++++++++- GPU/Vulkan/GPU_Vulkan.h | 14 +++ GPU/Vulkan/TextureCacheVulkan.cpp | 82 +++++++++--------- GPU/Vulkan/TextureCacheVulkan.h | 7 ++ GPU/Vulkan/VulkanUtil.cpp | 12 ++- GPU/Vulkan/VulkanUtil.h | 9 +- 13 files changed, 295 insertions(+), 161 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.h b/GPU/Common/DepalettizeShaderCommon.h index 7d2b02d113..933d4c02d9 100644 --- a/GPU/Common/DepalettizeShaderCommon.h +++ b/GPU/Common/DepalettizeShaderCommon.h @@ -20,4 +20,6 @@ #include "GPU/ge_constants.h" #include "GPU/Common/ShaderCommon.h" +static const int DEPAL_TEXTURE_OLD_AGE = 120; + void GenerateDepalShader(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language); diff --git a/GPU/D3D11/DepalettizeShaderD3D11.cpp b/GPU/D3D11/DepalettizeShaderD3D11.cpp index 59c558f7df..1ab84dbd38 100644 --- a/GPU/D3D11/DepalettizeShaderD3D11.cpp +++ b/GPU/D3D11/DepalettizeShaderD3D11.cpp @@ -29,8 +29,6 @@ #include "GPU/D3D11/D3D11Util.h" #include "GPU/Common/DepalettizeShaderCommon.h" -static const int DEPAL_TEXTURE_OLD_AGE = 120; - #ifdef _WIN32 #define SHADERLOG #endif diff --git a/GPU/GLES/DepalettizeShaderGLES.cpp b/GPU/GLES/DepalettizeShaderGLES.cpp index f18513753a..b6f5c2e7d6 100644 --- a/GPU/GLES/DepalettizeShaderGLES.cpp +++ b/GPU/GLES/DepalettizeShaderGLES.cpp @@ -26,8 +26,6 @@ #include "ext/native/gfx/GLStateCache.h" #include "GPU/Common/DepalettizeShaderCommon.h" -static const int DEPAL_TEXTURE_OLD_AGE = 120; - #ifdef _WIN32 #define SHADERLOG #endif diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index 2de073cabe..c785ee4372 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -15,10 +15,29 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - +#include "Common/Vulkan/VulkanContext.h" +#include "GPU/GPUState.h" +#include "GPU/Common/DepalettizeShaderCommon.h" #include "GPU/Vulkan/DepalettizeShaderVulkan.h" +#include "GPU/Vulkan/VulkanUtil.h" +#include "Common/Vulkan/VulkanImage.h" -DepalShaderCacheVulkan::DepalShaderCacheVulkan() { +static VkFormat GetClutDestFormat(GEPaletteFormat format) { + switch (format) { + case GE_CMODE_16BIT_ABGR4444: + return VK_FORMAT_R4G4B4A4_UNORM_PACK16; + case GE_CMODE_16BIT_ABGR5551: + return VK_FORMAT_A1R5G5B5_UNORM_PACK16; + case GE_CMODE_16BIT_BGR5650: + return VK_FORMAT_R5G6B5_UNORM_PACK16; + case GE_CMODE_32BIT_ABGR8888: + return VK_FORMAT_R8G8B8A8_UNORM; + } + return VK_FORMAT_UNDEFINED; +} + +DepalShaderCacheVulkan::DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan) + : draw_(draw), vulkan_(vulkan) { } @@ -26,22 +45,94 @@ DepalShaderCacheVulkan::~DepalShaderCacheVulkan() { } -DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { +DepalShaderVulkan *DepalShaderCacheVulkan::GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat) { + u32 id = GenerateShaderID(clutMode, pixelFormat); + + auto shader = cache_.find(id); + if (shader != cache_.end()) { + return shader->second; + } + + char *buffer = new char[2048]; + + VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS); + + GenerateDepalShader(buffer, pixelFormat, GLSL_VULKAN); + + std::string error; + VkShaderModule fshader = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, buffer, &error); + if (fshader == VK_NULL_HANDLE) { + return nullptr; + } + + VkPipeline pipeline = vulkan2D_->GetPipeline(rp, vshader_, fshader); + // Can delete the shader module now that the pipeline has been created. + // Maybe don't even need to queue it.. + vulkan_->Delete().QueueDeleteShaderModule(fshader); + + DepalShaderVulkan *depal = new DepalShaderVulkan(); + depal->pipeline = pipeline; + depal->code = buffer; + cache_[id] = depal; return nullptr; } -VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut) { - return nullptr; +VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat, u32 clutID, u32 *rawClut) { + const u32 realClutID = clutID ^ clutFormat; + + auto oldtex = texCache_.find(realClutID); + if (oldtex != texCache_.end()) { + oldtex->second->lastFrame = gpuStats.numFlips; + return oldtex->second->texture; + } + + VkFormat destFormat = GetClutDestFormat(clutFormat); + int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; + + VkBuffer pushBuffer; + uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer); + + VulkanTexture *vktex = new VulkanTexture(vulkan_, alloc_); + vktex->CreateDirect(cmd_, texturePixels, 1, 1, destFormat, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT, nullptr); + vktex->UploadMip(cmd_, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels); + vktex->EndCreate(cmd_); + + DepalTextureVulkan *tex = new DepalTextureVulkan(); + tex->texture = vktex; + tex->lastFrame = gpuStats.numFlips; + texCache_[realClutID] = tex; + return tex->texture; } -void DepalShaderCacheVulkan::Clear() {} +void DepalShaderCacheVulkan::Clear() { + for (auto shader = cache_.begin(); shader != cache_.end(); ++shader) { + // Delete the shader/pipeline too. + delete shader->second; + } + cache_.clear(); -void DepalShaderCacheVulkan::Decimate() {} + for (auto tex = texCache_.begin(); tex != texCache_.end(); ++tex) { + delete tex->second->texture; + delete tex->second; + } + texCache_.clear(); -u32 DepalShaderCacheVulkan::GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat) { - return 0; + // TODO: Delete vertex shader. } -bool DepalShaderCacheVulkan::CreateVertexShader() { - return false; +void DepalShaderCacheVulkan::Decimate() { + // We don't bother decimating the generated shaders, there are never very many of them. + for (auto tex = texCache_.begin(); tex != texCache_.end(); ) { + if (tex->second->lastFrame + DEPAL_TEXTURE_OLD_AGE < gpuStats.numFlips) { + delete tex->second->texture; + delete tex->second; + texCache_.erase(tex++); + } else { + ++tex; + } + } +} + +u32 DepalShaderCacheVulkan::GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat) { + return (clutMode & 0xFFFFFF) | (pixelFormat << 24); } diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.h b/GPU/Vulkan/DepalettizeShaderVulkan.h index 63faa1c8b6..fb2c3db4a4 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.h +++ b/GPU/Vulkan/DepalettizeShaderVulkan.h @@ -20,42 +20,59 @@ #include #include "Common/CommonTypes.h" +#include "Common/Vulkan/VulkanContext.h" +#include "Common/Vulkan/VulkanImage.h" +#include "Common/Vulkan/VulkanMemory.h" #include "GPU/ge_constants.h" +#include "thin3d/thin3d.h" class DepalShaderVulkan { public: - /* - GLuint program; - GLuint fragShader; - GLint a_position; - GLint a_texcoord0; - */ + ~DepalShaderVulkan() { + delete[] code; + } + // A Vulkan2D pipeline. Set texture to slot 0 and palette texture to slot 1. + VkPipeline pipeline; + const char *code = nullptr;; }; class DepalTextureVulkan { public: - int texture; + VulkanTexture *texture; int lastFrame; }; class VulkanTexture; +class Vulkan2D; // Caches both shaders and palette textures. // Could even avoid bothering with palette texture and just use uniform data... class DepalShaderCacheVulkan { public: - DepalShaderCacheVulkan(); + DepalShaderCacheVulkan(Draw::DrawContext *draw, VulkanContext *vulkan); ~DepalShaderCacheVulkan(); // This also uploads the palette and binds the correct texture. - DepalShaderVulkan *GetDepalettizeShader(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); + DepalShaderVulkan *GetDepalettizeShader(uint32_t clutMode, GEBufferFormat pixelFormat); VulkanTexture *GetClutTexture(GEPaletteFormat clutFormat, const u32 clutHash, u32 *rawClut); void Clear(); void Decimate(); + void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; } + void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } + void SetAllocator(VulkanDeviceAllocator *alloc) { alloc_ = alloc; } + void SetVShader(VkShaderModule vshader) { vshader_ = vshader; } + private: - u32 GenerateShaderID(GEPaletteFormat clutFormat, GEBufferFormat pixelFormat); - bool CreateVertexShader(); + u32 GenerateShaderID(uint32_t clutMode, GEBufferFormat pixelFormat); + + VkCommandBuffer cmd_ = VK_NULL_HANDLE; + Draw::DrawContext *draw_ = nullptr; + VulkanContext *vulkan_ = nullptr; + VulkanPushBuffer *push_ = nullptr; + VulkanDeviceAllocator *alloc_ = nullptr; + VkShaderModule vshader_ = VK_NULL_HANDLE; + Vulkan2D *vulkan2D_ = nullptr; // GLuint vertexShader_; std::map cache_; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 84bb6faa80..4bf271f7e6 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -88,9 +88,8 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk convBufSize_(0), textureCacheVulkan_(nullptr), shaderManagerVulkan_(nullptr), - curFrame_(0), pipelinePostShader_(VK_NULL_HANDLE), - vulkan2D_(vulkan) { + depalVulkan_(draw, vulkan) { InitDeviceObjects(); @@ -101,7 +100,6 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk FramebufferManagerVulkan::~FramebufferManagerVulkan() { delete[] convBuf_; - vulkan2D_.Shutdown(); DestroyDeviceObjects(); } @@ -121,23 +119,12 @@ void FramebufferManagerVulkan::SetDrawEngine(DrawEngineVulkan *td) { } void FramebufferManagerVulkan::InitDeviceObjects() { - // Initialize framedata - for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { - frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024); - } - - pipelineCache2D_ = vulkan_->CreatePipelineCache(); - std::string fs_errors, vs_errors; fsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_FRAGMENT_BIT, tex_fs, &fs_errors); vsBasicTex_ = CompileShaderModule(vulkan_, VK_SHADER_STAGE_VERTEX_BIT, tex_vs, &vs_errors); assert(fsBasicTex_ != VK_NULL_HANDLE); assert(vsBasicTex_ != VK_NULL_HANDLE); - // Prime the 2D pipeline cache. - // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_); - // vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_); - VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -153,13 +140,6 @@ void FramebufferManagerVulkan::InitDeviceObjects() { } void FramebufferManagerVulkan::DestroyDeviceObjects() { - for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { - if (frameData_[i].push_) { - frameData_[i].push_->Destroy(vulkan_); - delete frameData_[i].push_; - frameData_[i].push_ = nullptr; - } - } delete drawPixelsTex_; drawPixelsTex_ = nullptr; @@ -172,32 +152,29 @@ void FramebufferManagerVulkan::DestroyDeviceObjects() { vulkan_->Delete().QueueDeleteSampler(linearSampler_); if (nearestSampler_ != VK_NULL_HANDLE) vulkan_->Delete().QueueDeleteSampler(nearestSampler_); - // pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_. - if (pipelineCache2D_ != VK_NULL_HANDLE) - vulkan_->Delete().QueueDeletePipelineCache(pipelineCache2D_); } void FramebufferManagerVulkan::NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth) { - float x, y, w, h; - CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); + float x, y, w, h; + CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL); - int mask = 0; - // The Clear detection takes care of doing a regular draw instead if separate masking - // of color and alpha is needed, so we can just treat them as the same. - if (clearColor || clearAlpha) - mask |= Draw::FBChannel::FB_COLOR_BIT; - if (clearDepth) - mask |= Draw::FBChannel::FB_DEPTH_BIT; - if (clearAlpha) - mask |= Draw::FBChannel::FB_STENCIL_BIT; + int mask = 0; + // The Clear detection takes care of doing a regular draw instead if separate masking + // of color and alpha is needed, so we can just treat them as the same. + if (clearColor || clearAlpha) + mask |= Draw::FBChannel::FB_COLOR_BIT; + if (clearDepth) + mask |= Draw::FBChannel::FB_DEPTH_BIT; + if (clearAlpha) + mask |= Draw::FBChannel::FB_STENCIL_BIT; - draw_->Clear(mask, color, depth, 0); - if (clearColor || clearAlpha) { - SetColorUpdated(gstate_c.skipDrawReason); - } - if (clearDepth) { - SetDepthUpdated(); - } + draw_->Clear(mask, color, depth, 0); + if (clearColor || clearAlpha) { + SetColorUpdated(gstate_c.skipDrawReason); + } + if (clearDepth) { + SetDepthUpdated(); + } } void FramebufferManagerVulkan::UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight) { @@ -242,6 +219,7 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor // Initialize backbuffer texture for DrawPixels drawPixelsTexFormat_ = srcPixelFormat; } else { + // TODO: We may want to double-buffer these, when we have more frames hanging about. drawPixelsTex_->TransitionForUpload(initCmd); } @@ -298,7 +276,7 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor } VkBuffer buffer; - size_t offset = frameData_[curFrame_].push_->Push(data, width * height * 4, &buffer); + size_t offset = push_->Push(data, width * height * 4, &buffer); drawPixelsTex_->UploadMip(initCmd, 0, width, height, buffer, (uint32_t)offset, width); drawPixelsTex_->EndCreate(initCmd); @@ -357,22 +335,21 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa // TODO: Should probably use draw_ directly and not go low level - VulkanPushBuffer *push = frameData_[curFrame_].push_; VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW); if ((flags & DRAWTEX_KEEP_TEX) == 0) overrideImageView_ = VK_NULL_HANDLE; - VkDescriptorSet descSet = vulkan2D_.GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE); + VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE); VkBuffer vbuffer; - VkDeviceSize offset = push->Push(vtx, sizeof(vtx), &vbuffer); + VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer); renderManager->BindPipeline(cur2DPipeline_); - renderManager->Draw(vulkan2D_.GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4); + renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4); } void FramebufferManagerVulkan::Bind2DShader() { VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS); - cur2DPipeline_ = vulkan2D_.GetPipeline(pipelineCache2D_, rp, vsBasicTex_, fsBasicTex_); + cur2DPipeline_ = vulkan2D_->GetPipeline(rp, vsBasicTex_, fsBasicTex_); } void FramebufferManagerVulkan::BindPostShader(const PostShaderUniforms &uniforms) { @@ -608,31 +585,13 @@ void ConvertFromRGBA8888_Vulkan(u8 *dst, const u8 *src, u32 dstStride, u32 srcSt void FramebufferManagerVulkan::BeginFrameVulkan() { BeginFrame(); - - vulkan2D_.BeginFrame(); - - FrameData &frame = frameData_[curFrame_]; - - frame.push_->Reset(); - frame.push_->Begin(vulkan_); } void FramebufferManagerVulkan::EndFrame() { - // We flush to memory last requested framebuffer, if any. - // Only do this in the read-framebuffer modes. - FrameData &frame = frameData_[curFrame_]; - frame.push_->End(); - - vulkan2D_.EndFrame(); - - curFrame_++; - if (curFrame_ >= vulkan_->GetInflightFrames()) { - curFrame_ = 0; - } } void FramebufferManagerVulkan::DeviceLost() { - vulkan2D_.DeviceLost(); + vulkan2D_->DeviceLost(); DestroyAllFBOs(); DestroyDeviceObjects(); @@ -641,7 +600,7 @@ void FramebufferManagerVulkan::DeviceLost() { void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan) { vulkan_ = vulkan; - vulkan2D_.DeviceRestore(vulkan_); + vulkan2D_->DeviceRestore(vulkan_); InitDeviceObjects(); } diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index 46b76e49db..2ea5037c6b 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -22,6 +22,7 @@ #include "GPU/GPUInterface.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Vulkan/VulkanUtil.h" +#include "GPU/Vulkan/DepalettizeShaderVulkan.h" // TODO: Remove? enum VulkanFBOColorDepth { @@ -44,6 +45,8 @@ R"( vec2 texelDelta; vec4 time; )"; +class VulkanPushBuffer; + class FramebufferManagerVulkan : public FramebufferManagerCommon { public: FramebufferManagerVulkan(Draw::DrawContext *draw, VulkanContext *vulkan); @@ -52,6 +55,8 @@ public: void SetTextureCache(TextureCacheVulkan *tc); void SetShaderManager(ShaderManagerVulkan *sm); void SetDrawEngine(DrawEngineVulkan *td); + void SetVulkan2D(Vulkan2D *vk2d) { vulkan2D_ = vk2d; } + void SetPushBuffer(VulkanPushBuffer *push) { push_ = push; } // x,y,w,h are relative to destW, destH which fill out the target completely. void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override; @@ -105,28 +110,21 @@ private: // Used to keep track of command buffers here but have moved all that into Thin3D. // Used by DrawPixels - VulkanTexture *drawPixelsTex_; - GEBufferFormat drawPixelsTexFormat_; - - u8 *convBuf_; - u32 convBufSize_; + VulkanTexture *drawPixelsTex_ = nullptr; + GEBufferFormat drawPixelsTexFormat_ = GE_FORMAT_INVALID; + u8 *convBuf_ = nullptr; + u32 convBufSize_ = 0; TextureCacheVulkan *textureCacheVulkan_; ShaderManagerVulkan *shaderManagerVulkan_; DrawEngineVulkan *drawEngineVulkan_; + VulkanPushBuffer *push_; + DepalShaderCacheVulkan depalVulkan_; enum { MAX_COMMAND_BUFFERS = 32, }; - // Commandbuffers are handled internally in thin3d, one for each framebuffer pass. - struct FrameData { - VulkanPushBuffer *push_; - }; - - FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; - int curFrame_; - // This gets copied to the current frame's push buffer as needed. PostShaderUniforms postUniforms_; @@ -148,5 +146,5 @@ private: VkImageView overrideImageView_ = VK_NULL_HANDLE; // Simple 2D drawing engine. - Vulkan2D vulkan2D_; + Vulkan2D *vulkan2D_; }; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index f1fb20e9bc..3cb01856d1 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -76,7 +76,9 @@ static const VulkanCommandTableEntry commandTable[] = { GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) : GPUCommon(gfxCtx, draw), vulkan_((VulkanContext *)gfxCtx->GetAPIContext()), - drawEngine_(vulkan_, draw) { + drawEngine_(vulkan_, draw), + depalShaderCache_(draw, vulkan_), + vulkan2D_(vulkan_) { UpdateVsyncInterval(true); CheckGPUFeatures(); @@ -97,10 +99,14 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_); framebufferManagerVulkan_->SetDrawEngine(&drawEngine_); framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_); - textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); + framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_); textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_); + textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_); textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_); textureCacheVulkan_->SetDrawEngine(&drawEngine_); + textureCacheVulkan_->SetVulkan2D(&vulkan2D_); + + InitDeviceObjects(); // Sanity check gstate if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) { @@ -155,7 +161,9 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw) } GPU_Vulkan::~GPU_Vulkan() { + DestroyDeviceObjects(); framebufferManagerVulkan_->DestroyAllFBOs(); + vulkan2D_.Shutdown(); depalShaderCache_.Clear(); delete textureCacheVulkan_; delete pipelineManager_; @@ -209,9 +217,19 @@ void GPU_Vulkan::BeginHostFrame() { resized_ = false; textureCacheVulkan_->StartFrame(); - depalShaderCache_.Decimate(); + + + FrameData &frame = frameData_[curFrame_]; + + frame.push_->Reset(); + frame.push_->Begin(vulkan_); framebufferManagerVulkan_->BeginFrameVulkan(); + framebufferManagerVulkan_->SetPushBuffer(frameData_[curFrame_].push_); + depalShaderCache_.SetPushBuffer(frameData_[curFrame_].push_); + textureCacheVulkan_->SetPushBuffer(frameData_[curFrame_].push_); + + vulkan2D_.BeginFrame(); shaderManagerVulkan_->DirtyShader(); gstate_c.Dirty(DIRTY_ALL); @@ -226,6 +244,16 @@ void GPU_Vulkan::BeginHostFrame() { } void GPU_Vulkan::EndHostFrame() { + FrameData &frame = frameData_[curFrame_]; + frame.push_->End(); + + vulkan2D_.EndFrame(); + + curFrame_++; + if (curFrame_ >= vulkan_->GetInflightFrames()) { + curFrame_ = 0; + } + drawEngine_.EndFrame(); framebufferManagerVulkan_->EndFrame(); textureCacheVulkan_->EndFrame(); @@ -769,7 +797,26 @@ void GPU_Vulkan::FastLoadBoneMatrix(u32 target) { gstate.FastLoadBoneMatrix(target); } +void GPU_Vulkan::InitDeviceObjects() { + // Initialize framedata + for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { + frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024); + } +} + +void GPU_Vulkan::DestroyDeviceObjects() { + for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { + if (frameData_[i].push_) { + frameData_[i].push_->Destroy(vulkan_); + delete frameData_[i].push_; + frameData_[i].push_ = nullptr; + } + } +} + void GPU_Vulkan::DeviceLost() { + DestroyDeviceObjects(); + framebufferManagerVulkan_->DeviceLost(); drawEngine_.DeviceLost(); pipelineManager_->DeviceLost(); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 1e7dc06ec2..ccdf36b3a4 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -101,6 +101,10 @@ private: void ReinitializeInternal() override; inline void UpdateVsyncInterval(bool force); void UpdateCmdInfo(); + + void InitDeviceObjects(); + void DestroyDeviceObjects(); + static CommandInfo cmdInfo_[256]; VulkanContext *vulkan_; @@ -121,4 +125,14 @@ private: std::string reportingPrimaryInfo_; std::string reportingFullInfo_; + + // Simple 2D drawing engine. + Vulkan2D vulkan2D_; + + struct FrameData { + VulkanPushBuffer *push_; + }; + + FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{}; + int curFrame_ = 0; }; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 2ae17c63b1..ce5124aaa1 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -152,6 +152,11 @@ void TextureCacheVulkan::SetFramebufferManager(FramebufferManagerVulkan *fbManag framebufferManager_ = fbManager; } +void TextureCacheVulkan::SetVulkan2D(Vulkan2D *vk2d) { + vulkan2D_ = vk2d; + depalShaderCache_->SetVulkan2D(vk2d); +} + void TextureCacheVulkan::DeviceLost() { Clear(true); @@ -269,6 +274,8 @@ void TextureCacheVulkan::SetFramebufferSamplingParams(u16 bufferWidth, u16 buffe void TextureCacheVulkan::StartFrame() { InvalidateLastTexture(); + depalShaderCache_->Decimate(); + timesInvalidatedAllThisFrame_ = 0; texelsScaledThisFrame_ = 0; @@ -343,42 +350,24 @@ void TextureCacheVulkan::Unbind() { } void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { - DepalShaderVulkan *depal = nullptr; + DepalShaderVulkan *depalShader = nullptr; const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); if ((entry->status & TexCacheEntry::STATUS_DEPALETTIZE) && !g_Config.bDisableSlowFramebufEffects) { - // depal = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat); + depalShader = depalShaderCache_->GetDepalettizeShader(clutFormat, framebuffer->drawnFormat); } - if (depal) { - // VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); - // VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888); + if (depalShader) { + depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData()); + VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); - //depalFBO->BeginPass(cmd); + Draw::Framebuffer *depalFBO = framebufferManager_->GetTempFBO( + framebuffer->renderWidth, framebuffer->renderHeight, Draw::FBO_8888); + draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); - struct Pos { - Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) { - } - float x; - float y; - float z; - }; - struct UV { - UV(float u_, float v_) : u(u_), v(v_) { - } - float u; - float v; - }; - - Pos pos[4] = { - { -1, -1, -1 }, - { 1, -1, -1 }, - { 1, 1, -1 }, - { -1, 1, -1 }, - }; - UV uv[4] = { - { 0, 0 }, - { 1, 0 }, - { 1, 1 }, - { 0, 1 }, + Vulkan2D::Vertex verts[4] = { + { -1, -1, -1, 0, 0 }, + { 1, -1, -1, 1, 0 }, + { 1, 1, -1, 1, 1 }, + { -1, 1, -1, 0, 1 }, }; static const int indices[4] = { 0, 1, 3, 2 }; @@ -400,28 +389,32 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr const float top = v1 * invHalfHeight - 1.0f; const float bottom = v2 * invHalfHeight - 1.0f; // Points are: BL, BR, TR, TL. - pos[0] = Pos(left, bottom, -1.0f); - pos[1] = Pos(right, bottom, -1.0f); - pos[2] = Pos(right, top, -1.0f); - pos[3] = Pos(left, top, -1.0f); + verts[0].x = left; + verts[0].y = bottom; + verts[1].x = right; + verts[1].y = bottom; + verts[2].x = right; + verts[2].y = top; + verts[3].x = left; + verts[3].y = top; // And also the UVs, same order. const float uvleft = u1 * invWidth; const float uvright = u2 * invWidth; const float uvtop = v1 * invHeight; const float uvbottom = v2 * invHeight; - uv[0] = UV(uvleft, uvbottom); - uv[1] = UV(uvright, uvbottom); - uv[2] = UV(uvright, uvtop); - uv[3] = UV(uvleft, uvtop); + verts[0].u = uvleft; + verts[0].v = uvbottom; + verts[1].u = uvright; + verts[1].v = uvbottom; + verts[2].u = uvright; + verts[2].v = uvtop; + verts[3].u = uvleft; + verts[3].v = uvtop; } shaderManagerVulkan_->DirtyLastShader(); - //depalFBO->EndPass(cmd); - //depalFBO->TransitionToTexture(cmd); - //imageView = depalFBO->GetColorImageView(); - const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; @@ -429,7 +422,8 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); gstate_c.SetTextureSimpleAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE); - // imageView_ = depalFbo->getImageView(). + draw_->BindFramebufferAsTexture(depalFBO, 0, Draw::FB_COLOR_BIT, 0); + imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW); } else { entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE; diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 21beb9a18d..cae31787bb 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -61,6 +61,7 @@ private: DenseHashMap cache_; }; +class Vulkan2D; class TextureCacheVulkan : public TextureCacheCommon { public: @@ -83,6 +84,10 @@ public: void SetDrawEngine(DrawEngineVulkan *td) { drawEngine_ = td; } + void SetVulkan2D(Vulkan2D *vk2d); + void SetPushBuffer(VulkanPushBuffer *push) { + push_ = push; + } void ForgetLastTexture() override { lastBoundTexture = nullptr; @@ -119,6 +124,7 @@ private: VulkanContext *vulkan_; VulkanDeviceAllocator *allocator_; + VulkanPushBuffer *push_; SamplerCache samplerCache_; @@ -134,6 +140,7 @@ private: DepalShaderCacheVulkan *depalShaderCache_; ShaderManagerVulkan *shaderManagerVulkan_; DrawEngineVulkan *drawEngine_; + Vulkan2D *vulkan2D_; // Bound state to emulate an API similar to the others VkImageView imageView_ = VK_NULL_HANDLE; diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index caf06cbac8..af0240f736 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -36,6 +36,7 @@ void Vulkan2D::DestroyDeviceObjects() { for (int i = 0; i < vulkan_->GetInflightFrames(); i++) { if (frameData_[i].descPool != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteDescriptorPool(frameData_[i].descPool); + frameData_[i].descPool = VK_NULL_HANDLE; } } for (auto it : pipelines_) { @@ -52,9 +53,16 @@ void Vulkan2D::DestroyDeviceObjects() { vkDestroyPipelineLayout(device, pipelineLayout_, nullptr); pipelineLayout_ = VK_NULL_HANDLE; } + + // pipelineBasicTex_ and pipelineBasicTex_ come from vulkan2D_. + if (pipelineCache_ != VK_NULL_HANDLE) { + vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_); + pipelineCache_ = VK_NULL_HANDLE; + } } void Vulkan2D::InitDeviceObjects() { + pipelineCache_ = vulkan_->CreatePipelineCache(); // All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated. VkDescriptorSetLayoutBinding bindings[2] = {}; bindings[0].descriptorCount = 1; @@ -188,7 +196,7 @@ VkDescriptorSet Vulkan2D::GetDescriptorSet(VkImageView tex1, VkSampler sampler1, return desc; } -VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs) { +VkPipeline Vulkan2D::GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs) { PipelineKey key; key.vs = vs; key.fs = fs; @@ -298,7 +306,7 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade pipe.subpass = 0; VkPipeline pipeline; - VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), cache, 1, &pipe, nullptr, &pipeline); + VkResult result = vkCreateGraphicsPipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pipe, nullptr, &pipeline); if (result == VK_SUCCESS) { pipelines_[key] = pipeline; return pipeline; diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index 3c32a63fac..ccbbfb9cb1 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -56,7 +56,7 @@ public: void DeviceRestore(VulkanContext *vulkan); void Shutdown(); - VkPipeline GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs); + VkPipeline GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs); VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; } void BeginFrame(); void EndFrame(); @@ -72,9 +72,10 @@ private: void InitDeviceObjects(); void DestroyDeviceObjects(); - VulkanContext *vulkan_; - VkDescriptorSetLayout descriptorSetLayout_; - VkPipelineLayout pipelineLayout_; + VulkanContext *vulkan_ = nullptr; + VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; + VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; // Yes, another one... struct DescriptorSetKey {