mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-27 07:20:49 +00:00
Implement pipeline/shader cache for Vulkan, to avoid shader compile stutters on second and subsequent runs.
The raw pipeline cache got pretty large. Instead, store IDs like GL. There's still a disabled option to store the pipeline cache objects.
This commit is contained in:
parent
2d33d526b8
commit
614cabb115
@ -937,17 +937,6 @@ void VulkanContext::DestroyDevice() {
|
|||||||
device_ = nullptr;
|
device_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipelineCache VulkanContext::CreatePipelineCache() {
|
|
||||||
VkPipelineCache cache;
|
|
||||||
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
|
||||||
pc.pInitialData = nullptr;
|
|
||||||
pc.initialDataSize = 0;
|
|
||||||
pc.flags = 0;
|
|
||||||
VkResult res = vkCreatePipelineCache(device_, &pc, nullptr, &cache);
|
|
||||||
assert(VK_SUCCESS == res);
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule) {
|
bool VulkanContext::CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule) {
|
||||||
VkShaderModuleCreateInfo sm{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
VkShaderModuleCreateInfo sm{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||||
sm.pCode = spirv.data();
|
sm.pCode = spirv.data();
|
||||||
|
@ -142,8 +142,6 @@ public:
|
|||||||
|
|
||||||
VulkanDeleteList &Delete() { return globalDeleteList_; }
|
VulkanDeleteList &Delete() { return globalDeleteList_; }
|
||||||
|
|
||||||
VkPipelineCache CreatePipelineCache();
|
|
||||||
|
|
||||||
// The parameters are whatever the chosen window system wants.
|
// The parameters are whatever the chosen window system wants.
|
||||||
void InitSurface(WindowSystem winsys, void *data1, void *data2, int width = -1, int height = -1);
|
void InitSurface(WindowSystem winsys, void *data1, void *data2, int width = -1, int height = -1);
|
||||||
void ReinitSurface(int width = -1, int height = -1);
|
void ReinitSurface(int width = -1, int height = -1);
|
||||||
|
@ -88,6 +88,8 @@ public:
|
|||||||
return numDrawCalls;
|
return numDrawCalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VertexDecoder *GetVertexDecoder(u32 vtype);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void ClearTrackedVertexArrays() {}
|
virtual void ClearTrackedVertexArrays() {}
|
||||||
|
|
||||||
@ -106,8 +108,6 @@ protected:
|
|||||||
|
|
||||||
bool ApplyShaderBlending();
|
bool ApplyShaderBlending();
|
||||||
|
|
||||||
VertexDecoder *GetVertexDecoder(u32 vtype);
|
|
||||||
|
|
||||||
inline int IndexSize(u32 vtype) const {
|
inline int IndexSize(u32 vtype) const {
|
||||||
const u32 indexType = (vtype & GE_VTYPE_IDX_MASK);
|
const u32 indexType = (vtype & GE_VTYPE_IDX_MASK);
|
||||||
if (indexType == GE_VTYPE_IDX_16BIT) {
|
if (indexType == GE_VTYPE_IDX_16BIT) {
|
||||||
|
@ -75,6 +75,21 @@ void DecVtxFormat::ComputeID() {
|
|||||||
id = uvfmt | (c0fmt << 4) | (c1fmt << 8) | (nrmfmt << 12) | (posfmt << 16);
|
id = uvfmt | (c0fmt << 4) | (c1fmt << 8) | (nrmfmt << 12) | (posfmt << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DecVtxFormat::InitializeFromID(uint32_t id) {
|
||||||
|
this->id = id;
|
||||||
|
uvfmt = (id & 0xF);
|
||||||
|
c0fmt = ((id >> 4) & 0xF);
|
||||||
|
c1fmt = ((id >> 8) & 0xF);
|
||||||
|
nrmfmt = ((id >> 12) & 0xF);
|
||||||
|
posfmt = ((id >> 16) & 0xF);
|
||||||
|
uvoff = 0;
|
||||||
|
c0off = uvoff + DecFmtSize(uvfmt);
|
||||||
|
c1off = c0off + DecFmtSize(c0fmt);
|
||||||
|
nrmoff = c1off + DecFmtSize(c1fmt);
|
||||||
|
posoff = nrmoff + DecFmtSize(nrmfmt);
|
||||||
|
stride = posoff + DecFmtSize(posfmt);
|
||||||
|
}
|
||||||
|
|
||||||
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
|
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound) {
|
||||||
// Find index bounds. Could cache this in display lists.
|
// Find index bounds. Could cache this in display lists.
|
||||||
// Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck.
|
// Also, this could be greatly sped up with SSE2/NEON, although rarely a bottleneck.
|
||||||
|
@ -72,10 +72,11 @@ struct DecVtxFormat {
|
|||||||
u8 c1fmt; u8 c1off;
|
u8 c1fmt; u8 c1off;
|
||||||
u8 nrmfmt; u8 nrmoff;
|
u8 nrmfmt; u8 nrmoff;
|
||||||
u8 posfmt; u8 posoff;
|
u8 posfmt; u8 posoff;
|
||||||
short stride;
|
u8 stride;
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
void ComputeID();
|
void ComputeID();
|
||||||
|
void InitializeFromID(uint32_t id);
|
||||||
};
|
};
|
||||||
|
|
||||||
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound);
|
void GetIndexBounds(const void *inds, int count, u32 vertType, u16 *indexLowerBound, u16 *indexUpperBound);
|
||||||
|
@ -109,7 +109,7 @@ void DrawEngineGLES::DeviceRestore() {
|
|||||||
|
|
||||||
void DrawEngineGLES::InitDeviceObjects() {
|
void DrawEngineGLES::InitDeviceObjects() {
|
||||||
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
|
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
|
||||||
frameData_[i].pushVertex = new GLPushBuffer(render_, GL_ARRAY_BUFFER, 1024 * 1024);
|
frameData_[i].pushVertex = new GLPushBuffer(render_, GL_ARRAY_BUFFER, 256 * 1024);
|
||||||
frameData_[i].pushIndex = new GLPushBuffer(render_, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024);
|
frameData_[i].pushIndex = new GLPushBuffer(render_, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024);
|
||||||
|
|
||||||
render_->RegisterPushBuffer(i, frameData_[i].pushVertex);
|
render_->RegisterPushBuffer(i, frameData_[i].pushVertex);
|
||||||
|
@ -419,7 +419,7 @@ void GPU_GLES::BeginFrame() {
|
|||||||
|
|
||||||
GPUCommon::BeginFrame();
|
GPUCommon::BeginFrame();
|
||||||
|
|
||||||
// Save the cache from time to time. TODO: How often?
|
// Save the cache from time to time. TODO: How often? We save on exit, so shouldn't need to do this all that often.
|
||||||
if (!shaderCachePath_.empty() && (gpuStats.numFlips & 4095) == 0) {
|
if (!shaderCachePath_.empty() && (gpuStats.numFlips & 4095) == 0) {
|
||||||
shaderManagerGL_->Save(shaderCachePath_);
|
shaderManagerGL_->Save(shaderCachePath_);
|
||||||
}
|
}
|
||||||
|
@ -255,9 +255,7 @@ void DrawEngineVulkan::BeginFrame() {
|
|||||||
// TODO: How can we make this nicer...
|
// TODO: How can we make this nicer...
|
||||||
((TessellationDataTransferVulkan *)tessDataTransfer)->SetPushBuffer(frame->pushUBO);
|
((TessellationDataTransferVulkan *)tessDataTransfer)->SetPushBuffer(frame->pushUBO);
|
||||||
|
|
||||||
// TODO : Find a better place to do this.
|
|
||||||
if (!nullTexture_) {
|
if (!nullTexture_) {
|
||||||
ILOG("INIT : Creating null texture");
|
|
||||||
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
|
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
|
||||||
nullTexture_ = new VulkanTexture(vulkan_, textureCache_->GetAllocator());
|
nullTexture_ = new VulkanTexture(vulkan_, textureCache_->GetAllocator());
|
||||||
int w = 8;
|
int w = 8;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "Core/Config.h"
|
#include "Core/Config.h"
|
||||||
#include "Core/Reporting.h"
|
#include "Core/Reporting.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
#include "Core/ELF/ParamSFO.h"
|
||||||
|
|
||||||
#include "GPU/GPUState.h"
|
#include "GPU/GPUState.h"
|
||||||
#include "GPU/ge_constants.h"
|
#include "GPU/ge_constants.h"
|
||||||
@ -94,9 +95,57 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
|
|||||||
if (vulkan_->GetFeaturesEnabled().wideLines) {
|
if (vulkan_->GetFeaturesEnabled().wideLines) {
|
||||||
drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
|
drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load shader cache.
|
||||||
|
std::string discID = g_paramSFO.GetDiscID();
|
||||||
|
if (discID.size()) {
|
||||||
|
File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));
|
||||||
|
shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) + "/" + discID + ".vkshadercache";
|
||||||
|
|
||||||
|
LoadCache(shaderCachePath_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_Vulkan::LoadCache(std::string filename) {
|
||||||
|
PSP_SetLoading("Loading shader cache...");
|
||||||
|
// Actually precompiled by IsReady() since we're single-threaded.
|
||||||
|
FILE *f = File::OpenCFile(filename, "rb");
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// First compile shaders to SPIR-V, then load the pipeline cache and recreate the pipelines.
|
||||||
|
// It's when recreating the pipelines that the pipeline cache is useful - in the ideal case,
|
||||||
|
// it can just memcpy the finished shader binaries out of the pipeline cache file.
|
||||||
|
bool result = shaderManagerVulkan_->LoadCache(f);
|
||||||
|
if (result) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (!result) {
|
||||||
|
WARN_LOG(G3D, "Bad Vulkan pipeline cache");
|
||||||
|
// Bad cache file for this GPU/Driver/etc. Delete it.
|
||||||
|
File::Delete(filename);
|
||||||
|
} else {
|
||||||
|
INFO_LOG(G3D, "Loaded Vulkan pipeline cache.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_Vulkan::SaveCache(std::string filename) {
|
||||||
|
FILE *f = File::OpenCFile(filename, "wb");
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
shaderManagerVulkan_->SaveCache(f);
|
||||||
|
pipelineManager_->SaveCache(f, false, shaderManagerVulkan_);
|
||||||
|
INFO_LOG(G3D, "Saved Vulkan pipeline cache");
|
||||||
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_Vulkan::~GPU_Vulkan() {
|
GPU_Vulkan::~GPU_Vulkan() {
|
||||||
|
SaveCache(shaderCachePath_);
|
||||||
|
// Note: We save the cache in DeviceLost
|
||||||
DestroyDeviceObjects();
|
DestroyDeviceObjects();
|
||||||
framebufferManagerVulkan_->DestroyAllFBOs();
|
framebufferManagerVulkan_->DestroyAllFBOs();
|
||||||
vulkan2D_.Shutdown();
|
vulkan2D_.Shutdown();
|
||||||
@ -407,6 +456,9 @@ void GPU_Vulkan::DestroyDeviceObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GPU_Vulkan::DeviceLost() {
|
void GPU_Vulkan::DeviceLost() {
|
||||||
|
if (!shaderCachePath_.empty()) {
|
||||||
|
SaveCache(shaderCachePath_);
|
||||||
|
}
|
||||||
DestroyDeviceObjects();
|
DestroyDeviceObjects();
|
||||||
framebufferManagerVulkan_->DeviceLost();
|
framebufferManagerVulkan_->DeviceLost();
|
||||||
vulkan2D_.DeviceLost();
|
vulkan2D_.DeviceLost();
|
||||||
|
@ -80,6 +80,9 @@ private:
|
|||||||
void InitDeviceObjects();
|
void InitDeviceObjects();
|
||||||
void DestroyDeviceObjects();
|
void DestroyDeviceObjects();
|
||||||
|
|
||||||
|
void LoadCache(std::string filename);
|
||||||
|
void SaveCache(std::string filename);
|
||||||
|
|
||||||
VulkanContext *vulkan_;
|
VulkanContext *vulkan_;
|
||||||
FramebufferManagerVulkan *framebufferManagerVulkan_;
|
FramebufferManagerVulkan *framebufferManagerVulkan_;
|
||||||
TextureCacheVulkan *textureCacheVulkan_;
|
TextureCacheVulkan *textureCacheVulkan_;
|
||||||
@ -100,4 +103,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
|
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
|
||||||
|
|
||||||
|
std::string shaderCachePath_;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "profiler/profiler.h"
|
#include "profiler/profiler.h"
|
||||||
|
|
||||||
@ -8,9 +9,10 @@
|
|||||||
#include "GPU/Vulkan/VulkanUtil.h"
|
#include "GPU/Vulkan/VulkanUtil.h"
|
||||||
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
#include "GPU/Vulkan/PipelineManagerVulkan.h"
|
||||||
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
#include "GPU/Vulkan/ShaderManagerVulkan.h"
|
||||||
|
#include "GPU/Common/DrawEngineCommon.h"
|
||||||
|
|
||||||
PipelineManagerVulkan::PipelineManagerVulkan(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(256) {
|
PipelineManagerVulkan::PipelineManagerVulkan(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(256) {
|
||||||
pipelineCache_ = vulkan->CreatePipelineCache();
|
// The pipeline cache is created on demand (or explicitly through Load).
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineManagerVulkan::~PipelineManagerVulkan() {
|
PipelineManagerVulkan::~PipelineManagerVulkan() {
|
||||||
@ -40,7 +42,7 @@ void PipelineManagerVulkan::DeviceLost() {
|
|||||||
|
|
||||||
void PipelineManagerVulkan::DeviceRestore(VulkanContext *vulkan) {
|
void PipelineManagerVulkan::DeviceRestore(VulkanContext *vulkan) {
|
||||||
vulkan_ = vulkan;
|
vulkan_ = vulkan;
|
||||||
pipelineCache_ = vulkan->CreatePipelineCache();
|
// The pipeline cache is created on demand.
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeclTypeInfo {
|
struct DeclTypeInfo {
|
||||||
@ -97,7 +99,7 @@ static int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const D
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], const DecVtxFormat &decFmt) {
|
static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[]) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION);
|
VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION);
|
||||||
VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD);
|
VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD);
|
||||||
@ -223,7 +225,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
|||||||
attributeCount = SetupVertexAttribs(attrs, *decFmt);
|
attributeCount = SetupVertexAttribs(attrs, *decFmt);
|
||||||
vertexStride = decFmt->stride;
|
vertexStride = decFmt->stride;
|
||||||
} else {
|
} else {
|
||||||
attributeCount = SetupVertexAttribsPretransformed(attrs, *decFmt);
|
attributeCount = SetupVertexAttribsPretransformed(attrs);
|
||||||
vertexStride = 36;
|
vertexStride = 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,6 +295,12 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
|
|||||||
}
|
}
|
||||||
|
|
||||||
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layout, VkRenderPass renderPass, const VulkanPipelineRasterStateKey &rasterKey, const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform) {
|
||||||
|
if (!pipelineCache_) {
|
||||||
|
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
|
||||||
|
assert(VK_SUCCESS == res);
|
||||||
|
}
|
||||||
|
|
||||||
VulkanPipelineKey key{};
|
VulkanPipelineKey key{};
|
||||||
_assert_msg_(G3D, renderPass, "Can't create a pipeline with a null renderpass");
|
_assert_msg_(G3D, renderPass, "Can't create a pipeline with a null renderpass");
|
||||||
|
|
||||||
@ -301,7 +309,7 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VkPipelineLayout layo
|
|||||||
key.useHWTransform = useHwTransform;
|
key.useHWTransform = useHwTransform;
|
||||||
key.vShader = vs->GetModule();
|
key.vShader = vs->GetModule();
|
||||||
key.fShader = fs->GetModule();
|
key.fShader = fs->GetModule();
|
||||||
key.vtxDecId = useHwTransform ? decFmt->id : 0;
|
key.vtxFmtId = useHwTransform ? decFmt->id : 0;
|
||||||
|
|
||||||
auto iter = pipelines_.Get(key);
|
auto iter = pipelines_.Get(key);
|
||||||
if (iter)
|
if (iter)
|
||||||
@ -459,9 +467,9 @@ std::string PipelineManagerVulkan::DebugGetObjectString(std::string id, DebugSha
|
|||||||
if (pipelineKey.useHWTransform) {
|
if (pipelineKey.useHWTransform) {
|
||||||
str << "HWX ";
|
str << "HWX ";
|
||||||
}
|
}
|
||||||
if (pipelineKey.vtxDecId) {
|
if (pipelineKey.vtxFmtId) {
|
||||||
str << "V(";
|
str << "V(";
|
||||||
str << StringFromFormat("%08x", pipelineKey.vtxDecId); // TODO: Format nicer.
|
str << StringFromFormat("%08x", pipelineKey.vtxFmtId); // TODO: Format nicer.
|
||||||
str << ") ";
|
str << ") ";
|
||||||
} else {
|
} else {
|
||||||
str << "SWX ";
|
str << "SWX ";
|
||||||
@ -492,3 +500,145 @@ void PipelineManagerVulkan::SetLineWidth(float lineWidth) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For some reason this struct is only defined in the spec, not in the headers.
|
||||||
|
struct VkPipelineCacheHeader {
|
||||||
|
uint32_t headerSize;
|
||||||
|
VkPipelineCacheHeaderVersion version;
|
||||||
|
uint32_t vendorId;
|
||||||
|
uint32_t deviceId;
|
||||||
|
uint8_t uuid[VK_UUID_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager) {
|
||||||
|
size_t dataSize = 0;
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
if (saveRawPipelineCache) {
|
||||||
|
VkResult result = vkGetPipelineCacheData(vulkan_->GetDevice(), pipelineCache_, &dataSize, nullptr);
|
||||||
|
uint32_t size = (uint32_t)dataSize;
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
size = 0;
|
||||||
|
fwrite(&size, sizeof(size), 1, file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::unique_ptr<uint8_t[]> buffer(new uint8_t[dataSize]);
|
||||||
|
vkGetPipelineCacheData(vulkan_->GetDevice(), pipelineCache_, &dataSize, buffer.get());
|
||||||
|
size = (uint32_t)dataSize;
|
||||||
|
fwrite(&size, sizeof(size), 1, file);
|
||||||
|
fwrite(buffer.get(), 1, size, file);
|
||||||
|
NOTICE_LOG(G3D, "Saved Vulkan pipeline cache (%d bytes).", (int)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t seekPosOnFailure = ftell(file);
|
||||||
|
// Write the number of pipelines.
|
||||||
|
size = (uint32_t)pipelines_.size();
|
||||||
|
fwrite(&size, sizeof(size), 1, file);
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
int count = 0;
|
||||||
|
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
|
||||||
|
if (failed)
|
||||||
|
return;
|
||||||
|
VulkanVertexShader *vshader = shaderManager->GetVertexShaderFromModule(pkey.vShader);
|
||||||
|
VulkanFragmentShader *fshader = shaderManager->GetFragmentShaderFromModule(pkey.fShader);
|
||||||
|
if (!vshader || !fshader) {
|
||||||
|
failed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StoredVulkanPipelineKey key{};
|
||||||
|
key.raster = pkey.raster;
|
||||||
|
key.useHWTransform = pkey.useHWTransform;
|
||||||
|
key.fShaderID = fshader->GetID();
|
||||||
|
key.vShaderID = vshader->GetID();
|
||||||
|
if (key.useHWTransform) {
|
||||||
|
// NOTE: This is not a vtype, but a decoded vertex format.
|
||||||
|
key.vtxFmtId = pkey.vtxFmtId;
|
||||||
|
}
|
||||||
|
fwrite(&key, sizeof(key), 1, file);
|
||||||
|
count++;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
ERROR_LOG(G3D, "Failed to write pipeline cache, some shader was missing");
|
||||||
|
// Write a zero in the right place so it doesn't try to load the pipelines next time.
|
||||||
|
size = 0;
|
||||||
|
fseek(file, (long)seekPosOnFailure, SEEK_SET);
|
||||||
|
fwrite(&size, sizeof(size), 1, file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d pipelines).", (int)count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, DrawEngineCommon *drawEngine, VkPipelineLayout layout, VkRenderPass renderPass) {
|
||||||
|
uint32_t size = 0;
|
||||||
|
if (loadRawPipelineCache) {
|
||||||
|
fread(&size, sizeof(size), 1, file);
|
||||||
|
if (!size) {
|
||||||
|
WARN_LOG(G3D, "Zero-sized Vulkan pipeline cache.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
|
||||||
|
fread(buffer.get(), 1, size, file);
|
||||||
|
// Verify header.
|
||||||
|
VkPipelineCacheHeader *header = (VkPipelineCacheHeader *)buffer.get();
|
||||||
|
if (header->version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) {
|
||||||
|
// Bad header, don't do anything.
|
||||||
|
WARN_LOG(G3D, "Bad Vulkan pipeline cache header - ignoring");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (0 != memcmp(header->uuid, vulkan_->GetPhysicalDeviceProperties().pipelineCacheUUID, VK_UUID_SIZE)) {
|
||||||
|
// Wrong hardware/driver/etc.
|
||||||
|
WARN_LOG(G3D, "Bad Vulkan pipeline cache UUID - ignoring");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
pc.pInitialData = buffer.get();
|
||||||
|
pc.initialDataSize = size;
|
||||||
|
pc.flags = 0;
|
||||||
|
VkPipelineCache cache;
|
||||||
|
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &cache);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!pipelineCache_) {
|
||||||
|
pipelineCache_ = cache;
|
||||||
|
} else {
|
||||||
|
vkMergePipelineCaches(vulkan_->GetDevice(), pipelineCache_, 1, &cache);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!pipelineCache_) {
|
||||||
|
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
|
||||||
|
}
|
||||||
|
NOTICE_LOG(G3D, "Loaded Vulkan pipeline cache (%d bytes).", (int)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the number of pipelines.
|
||||||
|
fread(&size, sizeof(size), 1, file);
|
||||||
|
|
||||||
|
NOTICE_LOG(G3D, "Creating %d pipelines...", size);
|
||||||
|
bool failed = false;
|
||||||
|
for (uint32_t i = 0; i < size; i++) {
|
||||||
|
if (failed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
StoredVulkanPipelineKey key;
|
||||||
|
fread(&key, sizeof(key), 1, file);
|
||||||
|
VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID);
|
||||||
|
VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID);
|
||||||
|
if (!vs || !fs) {
|
||||||
|
failed = true;
|
||||||
|
ERROR_LOG(G3D, "Failed to find vs or fs in of pipeline %d in cache", (int)i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DecVtxFormat fmt;
|
||||||
|
fmt.InitializeFromID(key.vtxFmtId);
|
||||||
|
GetOrCreatePipeline(layout, renderPass, key.raster,
|
||||||
|
key.useHWTransform ? &fmt : 0,
|
||||||
|
vs, fs, key.useHWTransform);
|
||||||
|
}
|
||||||
|
NOTICE_LOG(G3D, "Recreated Vulkan pipeline cache (%d pipelines).", (int)size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -42,7 +42,7 @@ struct VulkanPipelineKey {
|
|||||||
VkRenderPass renderPass;
|
VkRenderPass renderPass;
|
||||||
VkShaderModule vShader;
|
VkShaderModule vShader;
|
||||||
VkShaderModule fShader;
|
VkShaderModule fShader;
|
||||||
uint32_t vtxDecId;
|
uint32_t vtxFmtId;
|
||||||
bool useHWTransform;
|
bool useHWTransform;
|
||||||
|
|
||||||
void ToString(std::string *str) const {
|
void ToString(std::string *str) const {
|
||||||
@ -54,6 +54,14 @@ struct VulkanPipelineKey {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StoredVulkanPipelineKey {
|
||||||
|
VulkanPipelineRasterStateKey raster;
|
||||||
|
VShaderID vShaderID;
|
||||||
|
FShaderID fShaderID;
|
||||||
|
uint32_t vtxFmtId;
|
||||||
|
bool useHWTransform;
|
||||||
|
};
|
||||||
|
|
||||||
enum PipelineFlags {
|
enum PipelineFlags {
|
||||||
PIPELINE_FLAG_USES_BASE_UB = (1 << 0),
|
PIPELINE_FLAG_USES_BASE_UB = (1 << 0),
|
||||||
PIPELINE_FLAG_USES_LIGHT_UB = (1 << 1),
|
PIPELINE_FLAG_USES_LIGHT_UB = (1 << 1),
|
||||||
@ -74,6 +82,8 @@ struct VulkanPipeline {
|
|||||||
class VulkanContext;
|
class VulkanContext;
|
||||||
class VulkanVertexShader;
|
class VulkanVertexShader;
|
||||||
class VulkanFragmentShader;
|
class VulkanFragmentShader;
|
||||||
|
class ShaderManagerVulkan;
|
||||||
|
class DrawEngineCommon;
|
||||||
|
|
||||||
class PipelineManagerVulkan {
|
class PipelineManagerVulkan {
|
||||||
public:
|
public:
|
||||||
@ -93,9 +103,13 @@ public:
|
|||||||
std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
std::string DebugGetObjectString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
||||||
std::vector<std::string> DebugGetObjectIDs(DebugShaderType type);
|
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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DenseHashMap<VulkanPipelineKey, VulkanPipeline *, nullptr> pipelines_;
|
DenseHashMap<VulkanPipelineKey, VulkanPipeline *, nullptr> pipelines_;
|
||||||
VkPipelineCache pipelineCache_;
|
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
|
||||||
VulkanContext *vulkan_;
|
VulkanContext *vulkan_;
|
||||||
float lineWidth_ = 1.0f;
|
float lineWidth_ = 1.0f;
|
||||||
};
|
};
|
||||||
|
@ -40,8 +40,8 @@
|
|||||||
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
#include "GPU/Vulkan/FragmentShaderGeneratorVulkan.h"
|
||||||
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
#include "GPU/Vulkan/VertexShaderGeneratorVulkan.h"
|
||||||
|
|
||||||
VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, const char *code, bool useHWTransform)
|
VulkanFragmentShader::VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, const char *code)
|
||||||
: vulkan_(vulkan), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(0) {
|
: vulkan_(vulkan), id_(id), failed_(false), module_(0) {
|
||||||
PROFILE_THIS_SCOPE("shadercomp");
|
PROFILE_THIS_SCOPE("shadercomp");
|
||||||
source_ = code;
|
source_ = code;
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, int vertType, bool useHWTransform, bool usesLighting)
|
VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform, bool usesLighting)
|
||||||
: vulkan_(vulkan), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(VK_NULL_HANDLE), usesLighting_(usesLighting) {
|
: vulkan_(vulkan), id_(id), failed_(false), useHWTransform_(useHWTransform), module_(VK_NULL_HANDLE), usesLighting_(usesLighting) {
|
||||||
PROFILE_THIS_SCOPE("shadercomp");
|
PROFILE_THIS_SCOPE("shadercomp");
|
||||||
source_ = code;
|
source_ = code;
|
||||||
@ -254,7 +254,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
|
|||||||
// Vertex shader not in cache. Let's compile it.
|
// Vertex shader not in cache. Let's compile it.
|
||||||
bool usesLighting;
|
bool usesLighting;
|
||||||
GenerateVulkanGLSLVertexShader(VSID, codeBuffer_, &usesLighting);
|
GenerateVulkanGLSLVertexShader(VSID, codeBuffer_, &usesLighting);
|
||||||
vs = new VulkanVertexShader(vulkan_, VSID, codeBuffer_, vertType, useHWTransform, usesLighting);
|
vs = new VulkanVertexShader(vulkan_, VSID, codeBuffer_, useHWTransform, usesLighting);
|
||||||
vsCache_.Insert(VSID, vs);
|
vsCache_.Insert(VSID, vs);
|
||||||
}
|
}
|
||||||
lastVSID_ = VSID;
|
lastVSID_ = VSID;
|
||||||
@ -263,7 +263,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
|
|||||||
if (!fs) {
|
if (!fs) {
|
||||||
// Fragment shader not in cache. Let's compile it.
|
// Fragment shader not in cache. Let's compile it.
|
||||||
GenerateVulkanGLSLFragmentShader(FSID, codeBuffer_);
|
GenerateVulkanGLSLFragmentShader(FSID, codeBuffer_);
|
||||||
fs = new VulkanFragmentShader(vulkan_, FSID, codeBuffer_, useHWTransform);
|
fs = new VulkanFragmentShader(vulkan_, FSID, codeBuffer_);
|
||||||
fsCache_.Insert(FSID, fs);
|
fsCache_.Insert(FSID, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,3 +323,89 @@ std::string ShaderManagerVulkan::DebugGetShaderString(std::string id, DebugShade
|
|||||||
return "N/A";
|
return "N/A";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VulkanVertexShader *ShaderManagerVulkan::GetVertexShaderFromModule(VkShaderModule module) {
|
||||||
|
VulkanVertexShader *vs = nullptr;
|
||||||
|
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *shader) {
|
||||||
|
if (shader->GetModule() == module)
|
||||||
|
vs = shader;
|
||||||
|
});
|
||||||
|
return vs;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderModule module) {
|
||||||
|
VulkanFragmentShader *fs = nullptr;
|
||||||
|
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *shader) {
|
||||||
|
if (shader->GetModule() == module)
|
||||||
|
fs = shader;
|
||||||
|
});
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shader cache.
|
||||||
|
//
|
||||||
|
// We simply store the IDs of the shaders used during gameplay. On next startup of
|
||||||
|
// the same game, we simply compile all the shaders from the start, so we don't have to
|
||||||
|
// compile them on the fly later. We also store the Vulkan pipeline cache, so if it contains
|
||||||
|
// pipelines compiled from SPIR-V matching these shaders, pipeline creation will be practically
|
||||||
|
// instantaneous.
|
||||||
|
|
||||||
|
#define CACHE_HEADER_MAGIC 0xff51f420
|
||||||
|
#define CACHE_VERSION 5
|
||||||
|
struct VulkanCacheHeader {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t featureFlags;
|
||||||
|
uint32_t reserved;
|
||||||
|
int numVertexShaders;
|
||||||
|
int numFragmentShaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ShaderManagerVulkan::LoadCache(FILE *f) {
|
||||||
|
VulkanCacheHeader header{};
|
||||||
|
fread(&header, sizeof(header), 1, f);
|
||||||
|
if (header.magic != CACHE_HEADER_MAGIC)
|
||||||
|
return false;
|
||||||
|
if (header.version != CACHE_VERSION)
|
||||||
|
return false;
|
||||||
|
if (header.featureFlags != gstate_c.featureFlags)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < header.numVertexShaders; i++) {
|
||||||
|
VShaderID id;
|
||||||
|
fread(&id, sizeof(id), 1, f);
|
||||||
|
bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
|
||||||
|
bool usesLighting;
|
||||||
|
GenerateVulkanGLSLVertexShader(id, codeBuffer_, &usesLighting);
|
||||||
|
VulkanVertexShader *vs = new VulkanVertexShader(vulkan_, id, codeBuffer_, useHWTransform, usesLighting);
|
||||||
|
vsCache_.Insert(id, vs);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < header.numFragmentShaders; i++) {
|
||||||
|
FShaderID id;
|
||||||
|
fread(&id, sizeof(id), 1, f);
|
||||||
|
GenerateVulkanGLSLFragmentShader(id, codeBuffer_);
|
||||||
|
VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan_, id, codeBuffer_);
|
||||||
|
fsCache_.Insert(id, fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTICE_LOG(G3D, "Loaded %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderManagerVulkan::SaveCache(FILE *f) {
|
||||||
|
VulkanCacheHeader header{};
|
||||||
|
header.magic = CACHE_HEADER_MAGIC;
|
||||||
|
header.version = CACHE_VERSION;
|
||||||
|
header.featureFlags = gstate_c.featureFlags;
|
||||||
|
header.reserved = 0;
|
||||||
|
header.numVertexShaders = (int)vsCache_.size();
|
||||||
|
header.numFragmentShaders = (int)fsCache_.size();
|
||||||
|
fwrite(&header, sizeof(header), 1, f);
|
||||||
|
vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *vs) {
|
||||||
|
fwrite(&id, sizeof(id), 1, f);
|
||||||
|
});
|
||||||
|
fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *fs) {
|
||||||
|
fwrite(&id, sizeof(id), 1, f);
|
||||||
|
});
|
||||||
|
NOTICE_LOG(G3D, "Saved %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders);
|
||||||
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "Common/Hashmaps.h"
|
#include "Common/Hashmaps.h"
|
||||||
#include "Common/Vulkan/VulkanMemory.h"
|
#include "Common/Vulkan/VulkanMemory.h"
|
||||||
@ -33,16 +35,16 @@ class VulkanPushBuffer;
|
|||||||
|
|
||||||
class VulkanFragmentShader {
|
class VulkanFragmentShader {
|
||||||
public:
|
public:
|
||||||
VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, const char *code, bool useHWTransform);
|
VulkanFragmentShader(VulkanContext *vulkan, FShaderID id, const char *code);
|
||||||
~VulkanFragmentShader();
|
~VulkanFragmentShader();
|
||||||
|
|
||||||
const std::string &source() const { return source_; }
|
const std::string &source() const { return source_; }
|
||||||
|
|
||||||
bool Failed() const { return failed_; }
|
bool Failed() const { return failed_; }
|
||||||
bool UseHWTransform() const { return useHWTransform_; }
|
|
||||||
|
|
||||||
std::string GetShaderString(DebugShaderStringType type) const;
|
std::string GetShaderString(DebugShaderStringType type) const;
|
||||||
VkShaderModule GetModule() const { return module_; }
|
VkShaderModule GetModule() const { return module_; }
|
||||||
|
const FShaderID &GetID() { return id_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VkShaderModule module_;
|
VkShaderModule module_;
|
||||||
@ -50,13 +52,12 @@ protected:
|
|||||||
VulkanContext *vulkan_;
|
VulkanContext *vulkan_;
|
||||||
std::string source_;
|
std::string source_;
|
||||||
bool failed_;
|
bool failed_;
|
||||||
bool useHWTransform_;
|
|
||||||
FShaderID id_;
|
FShaderID id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VulkanVertexShader {
|
class VulkanVertexShader {
|
||||||
public:
|
public:
|
||||||
VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, int vertType, bool useHWTransform, bool usesLighting);
|
VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform, bool usesLighting);
|
||||||
~VulkanVertexShader();
|
~VulkanVertexShader();
|
||||||
|
|
||||||
const std::string &source() const { return source_; }
|
const std::string &source() const { return source_; }
|
||||||
@ -69,6 +70,7 @@ public:
|
|||||||
|
|
||||||
std::string GetShaderString(DebugShaderStringType type) const;
|
std::string GetShaderString(DebugShaderStringType type) const;
|
||||||
VkShaderModule GetModule() const { return module_; }
|
VkShaderModule GetModule() const { return module_; }
|
||||||
|
const VShaderID &GetID() { return id_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VkShaderModule module_;
|
VkShaderModule module_;
|
||||||
@ -98,6 +100,12 @@ public:
|
|||||||
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
|
int GetNumVertexShaders() const { return (int)vsCache_.size(); }
|
||||||
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
|
int GetNumFragmentShaders() const { return (int)fsCache_.size(); }
|
||||||
|
|
||||||
|
// Used for saving/loading the cache. Don't need to be particularly fast.
|
||||||
|
VulkanVertexShader *GetVertexShaderFromID(VShaderID id) { return vsCache_.Get(id); }
|
||||||
|
VulkanFragmentShader *GetFragmentShaderFromID(FShaderID id) { return fsCache_.Get(id); }
|
||||||
|
VulkanVertexShader *GetVertexShaderFromModule(VkShaderModule module);
|
||||||
|
VulkanFragmentShader *GetFragmentShaderFromModule(VkShaderModule module);
|
||||||
|
|
||||||
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
|
std::vector<std::string> DebugGetShaderIDs(DebugShaderType type);
|
||||||
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
std::string DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType);
|
||||||
|
|
||||||
@ -115,6 +123,9 @@ public:
|
|||||||
return dest->PushAligned(&ub_lights, sizeof(ub_lights), uboAlignment_, buf);
|
return dest->PushAligned(&ub_lights, sizeof(ub_lights), uboAlignment_, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LoadCache(FILE *f);
|
||||||
|
void SaveCache(FILE *f);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
@ -62,7 +62,10 @@ void Vulkan2D::DestroyDeviceObjects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Vulkan2D::InitDeviceObjects() {
|
void Vulkan2D::InitDeviceObjects() {
|
||||||
pipelineCache_ = vulkan_->CreatePipelineCache();
|
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
|
||||||
|
assert(VK_SUCCESS == res);
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding bindings[2] = {};
|
VkDescriptorSetLayoutBinding bindings[2] = {};
|
||||||
// Texture.
|
// Texture.
|
||||||
bindings[0].descriptorCount = 1;
|
bindings[0].descriptorCount = 1;
|
||||||
@ -80,7 +83,7 @@ void Vulkan2D::InitDeviceObjects() {
|
|||||||
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||||
dsl.bindingCount = 2;
|
dsl.bindingCount = 2;
|
||||||
dsl.pBindings = bindings;
|
dsl.pBindings = bindings;
|
||||||
VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
|
res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
|
||||||
assert(VK_SUCCESS == res);
|
assert(VK_SUCCESS == res);
|
||||||
|
|
||||||
VkDescriptorPoolSize dpTypes[1];
|
VkDescriptorPoolSize dpTypes[1];
|
||||||
|
@ -773,7 +773,9 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
|
|||||||
res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_);
|
res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_);
|
||||||
assert(VK_SUCCESS == res);
|
assert(VK_SUCCESS == res);
|
||||||
|
|
||||||
pipelineCache_ = vulkan_->CreatePipelineCache();
|
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
|
||||||
|
res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
|
||||||
|
assert(VK_SUCCESS == res);
|
||||||
|
|
||||||
renderManager_.SetSplitSubmit(splitSubmit);
|
renderManager_.SetSplitSubmit(splitSubmit);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user