mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #10834 from hrydgard/vulkan-shader-cache-renderpasses
Include renderpass definition in Vulkan shader cache entries, should make it more effective again.
This commit is contained in:
commit
c2d5ce6c3e
9 changed files with 101 additions and 50 deletions
|
@ -131,7 +131,7 @@ void GPU_Vulkan::LoadCache(std::string filename) {
|
|||
VkRenderPass renderPass = g_Config.iRenderingMode == FB_BUFFERED_MODE ?
|
||||
(VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS) :
|
||||
(VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS);
|
||||
result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, &drawEngine_, drawEngine_.GetPipelineLayout(), renderPass);
|
||||
result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout(), renderPass);
|
||||
}
|
||||
fclose(f);
|
||||
if (!result) {
|
||||
|
@ -148,7 +148,7 @@ void GPU_Vulkan::SaveCache(std::string filename) {
|
|||
if (!f)
|
||||
return;
|
||||
shaderManagerVulkan_->SaveCache(f);
|
||||
pipelineManager_->SaveCache(f, false, shaderManagerVulkan_);
|
||||
pipelineManager_->SaveCache(f, false, shaderManagerVulkan_, draw_);
|
||||
INFO_LOG(G3D, "Saved Vulkan pipeline cache");
|
||||
fclose(f);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||
#include "GPU/Common/DrawEngineCommon.h"
|
||||
#include "ext/native/thin3d/thin3d.h"
|
||||
#include "ext/native/thin3d/VulkanRenderManager.h"
|
||||
#include "ext/native/thin3d/VulkanQueueRunner.h"
|
||||
|
||||
PipelineManagerVulkan::PipelineManagerVulkan(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(256) {
|
||||
// The pipeline cache is created on demand (or explicitly through Load).
|
||||
|
@ -540,7 +543,25 @@ struct VkPipelineCacheHeader {
|
|||
uint8_t uuid[VK_UUID_SIZE];
|
||||
};
|
||||
|
||||
void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager) {
|
||||
struct StoredVulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster;
|
||||
VShaderID vShaderID;
|
||||
FShaderID fShaderID;
|
||||
uint32_t vtxFmtId;
|
||||
bool useHWTransform;
|
||||
bool backbufferPass;
|
||||
VulkanQueueRunner::RPKey renderPassKey;
|
||||
|
||||
// For std::set. Better zero-initialize the struct properly for this to work.
|
||||
bool operator < (const StoredVulkanPipelineKey &other) const {
|
||||
return memcmp(this, &other, sizeof(*this)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) {
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
VulkanQueueRunner *queueRunner = rm->GetQueueRunner();
|
||||
|
||||
size_t dataSize = 0;
|
||||
uint32_t size;
|
||||
|
||||
|
@ -569,6 +590,7 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
|
|||
// Make sure the set of pipelines we write is "unique".
|
||||
std::set<StoredVulkanPipelineKey> keys;
|
||||
|
||||
// TODO: Use derivative pipelines when possible, helps Mali driver pipeline creation speed at least.
|
||||
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
|
||||
if (failed)
|
||||
return;
|
||||
|
@ -587,6 +609,14 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
|
|||
// NOTE: This is not a vtype, but a decoded vertex format.
|
||||
key.vtxFmtId = pkey.vtxFmtId;
|
||||
}
|
||||
// Figure out what kind of renderpass this pipeline uses.
|
||||
if (pkey.renderPass == queueRunner->GetBackbufferRenderPass()) {
|
||||
key.backbufferPass = true;
|
||||
key.renderPassKey = {};
|
||||
} else {
|
||||
key.backbufferPass = false;
|
||||
queueRunner->GetRenderPassKey(pkey.renderPass, &key.renderPassKey);
|
||||
}
|
||||
keys.insert(key);
|
||||
});
|
||||
|
||||
|
@ -610,7 +640,10 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
|
|||
NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size());
|
||||
}
|
||||
|
||||
bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, DrawEngineCommon *drawEngine, VkPipelineLayout layout, VkRenderPass renderPass) {
|
||||
bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, VkRenderPass renderPass) {
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
VulkanQueueRunner *queueRunner = rm->GetQueueRunner();
|
||||
|
||||
uint32_t size = 0;
|
||||
if (loadRawPipelineCache) {
|
||||
fread(&size, sizeof(size), 1, file);
|
||||
|
@ -673,6 +706,14 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha
|
|||
ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i);
|
||||
continue;
|
||||
}
|
||||
|
||||
VkRenderPass rp;
|
||||
if (key.backbufferPass) {
|
||||
rp = queueRunner->GetBackbufferRenderPass();
|
||||
} else {
|
||||
rp = queueRunner->GetRenderPass(key.renderPassKey);
|
||||
}
|
||||
|
||||
DecVtxFormat fmt;
|
||||
fmt.InitializeFromID(key.vtxFmtId);
|
||||
GetOrCreatePipeline(layout, renderPass, key.raster,
|
||||
|
|
|
@ -56,19 +56,6 @@ struct VulkanPipelineKey {
|
|||
std::string GetDescription(DebugShaderStringType stringType) const;
|
||||
};
|
||||
|
||||
struct StoredVulkanPipelineKey {
|
||||
VulkanPipelineRasterStateKey raster;
|
||||
VShaderID vShaderID;
|
||||
FShaderID fShaderID;
|
||||
uint32_t vtxFmtId;
|
||||
bool useHWTransform;
|
||||
|
||||
// For std::set. Better zero-initialize the struct properly for this to work.
|
||||
bool operator < (const StoredVulkanPipelineKey &other) const {
|
||||
return memcmp(this, &other, sizeof(*this)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
enum PipelineFlags {
|
||||
PIPELINE_FLAG_USES_LINES = (1 << 2),
|
||||
PIPELINE_FLAG_USES_BLEND_CONSTANT = (1 << 3),
|
||||
|
@ -109,8 +96,8 @@ public:
|
|||
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type);
|
||||
|
||||
// Saves data for faster creation next time.
|
||||
void SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager);
|
||||
bool LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, DrawEngineCommon *drawEngine, VkPipelineLayout layout, VkRenderPass renderPass);
|
||||
void SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext);
|
||||
bool LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout, VkRenderPass renderPass);
|
||||
|
||||
private:
|
||||
DenseHashMap<VulkanPipelineKey, VulkanPipeline *, nullptr> pipelines_;
|
||||
|
|
|
@ -350,7 +350,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM
|
|||
// instantaneous.
|
||||
|
||||
#define CACHE_HEADER_MAGIC 0xff51f420
|
||||
#define CACHE_VERSION 6
|
||||
#define CACHE_VERSION 9
|
||||
struct VulkanCacheHeader {
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
|
|
|
@ -506,6 +506,8 @@ handleELF:
|
|||
if (File::Exists(screenshotPath)) {
|
||||
if (readFileToString(false, screenshotPath.c_str(), info_->icon.data)) {
|
||||
info_->icon.dataLoaded = true;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Error loading screenshot data: '%s'", screenshotPath.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -795,6 +797,8 @@ void GameInfoCache::SetupTexture(std::shared_ptr<GameInfo> &info, Draw::DrawCont
|
|||
tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), (int)tex.data.size(), ImageFileType::DETECT);
|
||||
if (tex.texture) {
|
||||
tex.timeLoaded = time_now_d();
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed creating texture");
|
||||
}
|
||||
}
|
||||
if ((info->wantFlags & GAMEINFO_WANTBGDATA) == 0) {
|
||||
|
|
|
@ -312,9 +312,7 @@ void SavedataBrowser::Refresh() {
|
|||
if (!isState && File::Exists(path_ + fileInfo[i].name + "/PARAM.SFO"))
|
||||
isSaveData = true;
|
||||
|
||||
if (isSaveData) {
|
||||
savedataButtons.push_back(new SavedataButton(fileInfo[i].fullName, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)));
|
||||
} else if (isState) {
|
||||
if (isSaveData || isState) {
|
||||
savedataButtons.push_back(new SavedataButton(fileInfo[i].fullName, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::WRAP_CONTENT)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,8 +153,7 @@ void VulkanQueueRunner::InitBackbufferRenderPass() {
|
|||
assert(res == VK_SUCCESS);
|
||||
}
|
||||
|
||||
VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction, VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout, VkImageLayout finalColorLayout) {
|
||||
RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthLayout, finalColorLayout };
|
||||
VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
|
||||
auto pass = renderPasses_.Get(key);
|
||||
if (pass) {
|
||||
return pass;
|
||||
|
@ -163,7 +162,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
VkAttachmentDescription attachments[2] = {};
|
||||
attachments[0].format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
switch (colorLoadAction) {
|
||||
switch (key.colorLoadAction) {
|
||||
case VKRRenderPassAction::CLEAR:
|
||||
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
break;
|
||||
|
@ -182,14 +181,14 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
#else
|
||||
attachments[0].initialLayout = prevColorLayout;
|
||||
attachments[0].finalLayout = finalColorLayout;
|
||||
attachments[0].initialLayout = key.prevColorLayout;
|
||||
attachments[0].finalLayout = key.finalColorLayout;
|
||||
#endif
|
||||
attachments[0].flags = 0;
|
||||
|
||||
attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
switch (depthLoadAction) {
|
||||
switch (key.depthLoadAction) {
|
||||
case VKRRenderPassAction::CLEAR:
|
||||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
break;
|
||||
|
@ -200,7 +199,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
break;
|
||||
}
|
||||
switch (stencilLoadAction) {
|
||||
switch (key.stencilLoadAction) {
|
||||
case VKRRenderPassAction::CLEAR:
|
||||
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
break;
|
||||
|
@ -217,7 +216,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
#else
|
||||
attachments[1].initialLayout = prevDepthLayout;
|
||||
attachments[1].initialLayout = key.prevDepthLayout;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
#endif
|
||||
attachments[1].flags = 0;
|
||||
|
@ -244,7 +243,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
|
||||
VkSubpassDependency deps[2]{};
|
||||
int numDeps = 0;
|
||||
switch (prevColorLayout) {
|
||||
switch (key.prevColorLayout) {
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
// Already the right color layout. Unclear that we need to do a lot here..
|
||||
break;
|
||||
|
@ -266,11 +265,11 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(G3D, false, "GetRenderPass: Unexpected color layout %d", (int)prevColorLayout);
|
||||
_dbg_assert_msg_(G3D, false, "GetRenderPass: Unexpected color layout %d", (int)key.prevColorLayout);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (prevDepthLayout) {
|
||||
switch (key.prevDepthLayout) {
|
||||
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
|
||||
// Already the right depth layout. Unclear that we need to do a lot here..
|
||||
break;
|
||||
|
@ -287,7 +286,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)prevDepthLayout);
|
||||
_dbg_assert_msg_(G3D, false, "PerformBindRT: Unexpected depth layout %d", (int)key.prevDepthLayout);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -302,7 +301,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
|
|||
|
||||
// And the final transition.
|
||||
// Don't need to transition it if VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL.
|
||||
switch (finalColorLayout) {
|
||||
switch (key.finalColorLayout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
deps[numDeps].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
deps[numDeps].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
|
|
|
@ -174,11 +174,38 @@ public:
|
|||
|
||||
void CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels);
|
||||
|
||||
private:
|
||||
// Only call this from the render thread!
|
||||
VkRenderPass GetRenderPass(VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction,
|
||||
VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout, VkImageLayout finalColorLayout);
|
||||
struct RPKey {
|
||||
VKRRenderPassAction colorLoadAction;
|
||||
VKRRenderPassAction depthLoadAction;
|
||||
VKRRenderPassAction stencilLoadAction;
|
||||
VkImageLayout prevColorLayout;
|
||||
VkImageLayout prevDepthLayout;
|
||||
VkImageLayout finalColorLayout;
|
||||
// TODO: Also pre-transition depth, for copies etc.
|
||||
};
|
||||
|
||||
// Only call this from the render thread! Also ok during initialization (LoadCache).
|
||||
VkRenderPass GetRenderPass(
|
||||
VKRRenderPassAction colorLoadAction, VKRRenderPassAction depthLoadAction, VKRRenderPassAction stencilLoadAction,
|
||||
VkImageLayout prevColorLayout, VkImageLayout prevDepthLayout, VkImageLayout finalColorLayout) {
|
||||
RPKey key{ colorLoadAction, depthLoadAction, stencilLoadAction, prevColorLayout, prevDepthLayout, finalColorLayout };
|
||||
return GetRenderPass(key);
|
||||
}
|
||||
|
||||
VkRenderPass GetRenderPass(const RPKey &key);
|
||||
|
||||
bool GetRenderPassKey(VkRenderPass passToFind, RPKey *outKey) const {
|
||||
bool found = false;
|
||||
renderPasses_.Iterate([passToFind, &found, outKey](const RPKey &rpkey, VkRenderPass pass) {
|
||||
if (pass == passToFind) {
|
||||
found = true;
|
||||
*outKey = rpkey;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
private:
|
||||
void InitBackbufferRenderPass();
|
||||
|
||||
void PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
|
||||
|
@ -208,16 +235,6 @@ private:
|
|||
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
|
||||
VkRenderPass framebufferRenderPass_ = VK_NULL_HANDLE;
|
||||
|
||||
struct RPKey {
|
||||
VKRRenderPassAction colorAction;
|
||||
VKRRenderPassAction depthAction;
|
||||
VKRRenderPassAction stencilAction;
|
||||
VkImageLayout prevColorLayout;
|
||||
VkImageLayout prevDepthLayout;
|
||||
VkImageLayout finalColorLayout;
|
||||
// TODO: Also pre-transition depth, for copies etc.
|
||||
};
|
||||
|
||||
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
|
||||
// TODO: Create these on demand.
|
||||
DenseHashMap<RPKey, VkRenderPass, (VkRenderPass)VK_NULL_HANDLE> renderPasses_;
|
||||
|
|
|
@ -234,6 +234,11 @@ public:
|
|||
return vulkan_;
|
||||
}
|
||||
|
||||
// Be careful with this. Only meant to be used for fetching render passes for shader cache initialization.
|
||||
VulkanQueueRunner *GetQueueRunner() {
|
||||
return &queueRunner_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool InitBackbufferFramebuffers(int width, int height);
|
||||
bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
|
||||
|
|
Loading…
Add table
Reference in a new issue