[dxvk] Bump state cache version to v12

And remove its reliance on the old render pass format struct.
This commit is contained in:
Philip Rebohle 2022-07-02 21:23:00 +02:00
parent 39a2b1cb7a
commit e3a63d4faa
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 115 additions and 140 deletions

View File

@ -51,7 +51,7 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) {
DxvkGraphicsPipelineInstance* instance = this->findInstance(state, renderPass);
DxvkGraphicsPipelineInstance* instance = this->findInstance(state);
if (unlikely(!instance)) {
// Exit early if the state vector is invalid
@ -60,13 +60,13 @@ namespace dxvk {
// Prevent other threads from adding new instances and check again
std::lock_guard<dxvk::mutex> lock(m_mutex);
instance = this->findInstance(state, renderPass);
instance = this->findInstance(state);
if (!instance) {
// Keep pipeline object locked, at worst we're going to stall
// a state cache worker and the current thread needs priority.
instance = this->createInstance(state, renderPass);
this->writePipelineStateToCache(state, renderPass->format());
instance = this->createInstance(state);
this->writePipelineStateToCache(state);
}
}
@ -75,8 +75,7 @@ namespace dxvk {
void DxvkGraphicsPipeline::compilePipeline(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) {
const DxvkGraphicsPipelineStateInfo& state) {
// Exit early if the state vector is invalid
if (!this->validatePipelineState(state, false))
return;
@ -85,26 +84,24 @@ namespace dxvk {
// similar pipelines concurrently is fragile on some drivers
std::lock_guard<dxvk::mutex> lock(m_mutex);
if (!this->findInstance(state, renderPass))
this->createInstance(state, renderPass);
if (!this->findInstance(state))
this->createInstance(state);
}
DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::createInstance(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) {
VkPipeline pipeline = this->createPipeline(state, renderPass);
const DxvkGraphicsPipelineStateInfo& state) {
VkPipeline pipeline = this->createPipeline(state);
m_pipeMgr->m_numGraphicsPipelines += 1;
return &(*m_pipelines.emplace(state, renderPass, pipeline));
return &(*m_pipelines.emplace(state, pipeline));
}
DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) {
const DxvkGraphicsPipelineStateInfo& state) {
for (auto& instance : m_pipelines) {
if (instance.isCompatible(state, renderPass))
if (instance.isCompatible(state))
return &instance;
}
@ -113,8 +110,7 @@ namespace dxvk {
VkPipeline DxvkGraphicsPipeline::createPipeline(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) const {
const DxvkGraphicsPipelineStateInfo& state) const {
if (Logger::logLevel() <= LogLevel::Debug) {
Logger::debug("Compiling graphics pipeline...");
this->logPipelineState(LogLevel::Debug, state);
@ -551,8 +547,7 @@ namespace dxvk {
void DxvkGraphicsPipeline::writePipelineStateToCache(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPassFormat& format) const {
const DxvkGraphicsPipelineStateInfo& state) const {
if (m_pipeMgr->m_stateCache == nullptr)
return;
@ -563,7 +558,7 @@ namespace dxvk {
if (m_shaders.gs != nullptr) key.gs = m_shaders.gs->getShaderKey();
if (m_shaders.fs != nullptr) key.fs = m_shaders.fs->getShaderKey();
m_pipeMgr->m_stateCache->addGraphicsPipeline(key, state, format);
m_pipeMgr->m_stateCache->addGraphicsPipeline(key, state);
}

View File

@ -94,15 +94,12 @@ namespace dxvk {
DxvkGraphicsPipelineInstance()
: m_stateVector (),
m_renderPass (nullptr),
m_pipeline (VK_NULL_HANDLE) { }
DxvkGraphicsPipelineInstance(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* rp,
VkPipeline pipe)
: m_stateVector (state),
m_renderPass (rp),
m_pipeline (pipe) { }
/**
@ -113,10 +110,8 @@ namespace dxvk {
* \returns \c true if the specialization is compatible
*/
bool isCompatible(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* rp) {
return m_renderPass == rp
&& m_stateVector == state;
const DxvkGraphicsPipelineStateInfo& state) {
return m_stateVector == state;
}
/**
@ -130,7 +125,6 @@ namespace dxvk {
private:
DxvkGraphicsPipelineStateInfo m_stateVector;
const DxvkRenderPass* m_renderPass;
VkPipeline m_pipeline;
};
@ -212,11 +206,9 @@ namespace dxvk {
* Asynchronously compiles the given pipeline
* and stores the result for future use.
* \param [in] state Pipeline state vector
* \param [in] renderPass The render pass
*/
void compilePipeline(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass);
const DxvkGraphicsPipelineStateInfo& state);
private:
@ -238,16 +230,13 @@ namespace dxvk {
sync::List<DxvkGraphicsPipelineInstance> m_pipelines;
DxvkGraphicsPipelineInstance* createInstance(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass);
const DxvkGraphicsPipelineStateInfo& state);
DxvkGraphicsPipelineInstance* findInstance(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass);
const DxvkGraphicsPipelineStateInfo& state);
VkPipeline createPipeline(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) const;
const DxvkGraphicsPipelineStateInfo& state) const;
void destroyPipeline(
VkPipeline pipeline) const;
@ -264,8 +253,7 @@ namespace dxvk {
bool trusted) const;
void writePipelineStateToCache(
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPassFormat& format) const;
const DxvkGraphicsPipelineStateInfo& state) const;
void logPipelineState(
LogLevel level,

View File

@ -62,6 +62,14 @@ namespace dxvk {
return read(data);
}
bool read(DxvkRtInfo& data, uint32_t version) {
// v12 introduced this field
if (version < 12)
return true;
return read(data);
}
bool read(DxvkIlBinding& data, uint32_t version) {
if (version < 10) {
DxvkIlBindingV9 v9;
@ -76,6 +84,34 @@ namespace dxvk {
return read(data);
}
bool read(DxvkRenderPassFormatV11& data, uint32_t version) {
uint8_t sampleCount = 0;
uint8_t imageFormat = 0;
uint8_t imageLayout = 0;
if (!read(sampleCount)
|| !read(imageFormat)
|| !read(imageLayout))
return false;
data.sampleCount = VkSampleCountFlagBits(sampleCount);
data.depth.format = VkFormat(imageFormat);
data.depth.layout = unpackImageLayoutV11(imageLayout);
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (!read(imageFormat)
|| !read(imageLayout))
return false;
data.color[i].format = VkFormat(imageFormat);
data.color[i].layout = unpackImageLayoutV11(imageLayout);
}
return true;
}
template<typename T>
bool write(const T& data) {
if (m_size + sizeof(T) > MaxSize)
@ -114,6 +150,15 @@ namespace dxvk {
return true;
}
static VkImageLayout unpackImageLayoutV11(
uint8_t layout) {
switch (layout) {
case 0x80: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
case 0x81: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
default: return VkImageLayout(layout);
}
}
};
@ -199,8 +244,7 @@ namespace dxvk {
void DxvkStateCache::addGraphicsPipeline(
const DxvkStateCacheKey& shaders,
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPassFormat& format) {
const DxvkGraphicsPipelineStateInfo& state) {
if (shaders.vs.eq(g_nullShaderKey))
return;
@ -210,7 +254,7 @@ namespace dxvk {
for (auto e = entries.first; e != entries.second; e++) {
const DxvkStateCacheEntry& entry = m_entries[e->second];
if (entry.format.eq(format) && entry.gpState == state)
if (entry.gpState == state)
return;
}
@ -218,8 +262,7 @@ namespace dxvk {
std::unique_lock<dxvk::mutex> lock(m_writerLock);
m_writerQueue.push({ shaders, state,
DxvkComputePipelineStateInfo(),
format, g_nullHash });
DxvkComputePipelineStateInfo(), g_nullHash });
m_writerCond.notify_one();
createWriter();
@ -244,8 +287,7 @@ namespace dxvk {
std::unique_lock<dxvk::mutex> lock(m_writerLock);
m_writerQueue.push({ shaders,
DxvkGraphicsPipelineStateInfo(), state,
DxvkRenderPassFormat(), g_nullHash });
DxvkGraphicsPipelineStateInfo(), state, g_nullHash });
m_writerCond.notify_one();
createWriter();
@ -360,11 +402,7 @@ namespace dxvk {
for (auto e = entries.first; e != entries.second; e++) {
const auto& entry = m_entries[e->second];
if (m_passManager->validateRenderPassFormat(entry.format)) {
auto rp = m_passManager->getRenderPass(entry.format);
pipeline->compilePipeline(entry.gpState, rp);
}
pipeline->compilePipeline(entry.gpState);
}
} else {
auto pipeline = m_pipeManager->createComputePipeline(item.cp);
@ -504,31 +542,12 @@ namespace dxvk {
return false;
} else {
// Read packed render pass format
uint8_t sampleCount = 0;
uint8_t imageFormat = 0;
uint8_t imageLayout = 0;
if (!data.read(sampleCount, version)
|| !data.read(imageFormat, version)
|| !data.read(imageLayout, version))
return false;
entry.format.sampleCount = VkSampleCountFlagBits(sampleCount);
entry.format.depth.format = VkFormat(imageFormat);
entry.format.depth.layout = unpackImageLayout(imageLayout);
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
if (!data.read(imageFormat, version)
|| !data.read(imageLayout, version))
return false;
entry.format.color[i].format = VkFormat(imageFormat);
entry.format.color[i].layout = unpackImageLayout(imageLayout);
if (version < 12) {
DxvkRenderPassFormatV11 v11;
data.read(v11, version);
entry.gpState.rt = v11.convert();
}
if (!validateRenderPassFormat(entry.format))
return false;
// Read common pipeline state
if (!data.read(dummyBindingMask, version)
|| !data.read(entry.gpState.ia, version)
@ -537,6 +556,7 @@ namespace dxvk {
|| !data.read(entry.gpState.ms, version)
|| !data.read(entry.gpState.ds, version)
|| !data.read(entry.gpState.om, version)
|| !data.read(entry.gpState.rt, version)
|| !data.read(entry.gpState.dsFront, version)
|| !data.read(entry.gpState.dsBack, version))
return false;
@ -608,16 +628,6 @@ namespace dxvk {
}
if (!(stageMask & VK_SHADER_STAGE_COMPUTE_BIT)) {
// Pack render pass format
data.write(uint8_t(entry.format.sampleCount));
data.write(uint8_t(entry.format.depth.format));
data.write(packImageLayout(entry.format.depth.layout));
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
data.write(uint8_t(entry.format.color[i].format));
data.write(packImageLayout(entry.format.color[i].layout));
}
// Write out common pipeline state
data.write(entry.gpState.ia);
data.write(entry.gpState.il);
@ -625,6 +635,7 @@ namespace dxvk {
data.write(entry.gpState.ms);
data.write(entry.gpState.ds);
data.write(entry.gpState.om);
data.write(entry.gpState.rt);
data.write(entry.gpState.dsFront);
data.write(entry.gpState.dsBack);
@ -785,47 +796,4 @@ namespace dxvk {
return env::getEnvVar("DXVK_STATE_CACHE_PATH");
}
uint8_t DxvkStateCache::packImageLayout(
VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: return 0x80;
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: return 0x81;
default: return uint8_t(layout);
}
}
VkImageLayout DxvkStateCache::unpackImageLayout(
uint8_t layout) {
switch (layout) {
case 0x80: return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
case 0x81: return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
default: return VkImageLayout(layout);
}
}
bool DxvkStateCache::validateRenderPassFormat(
const DxvkRenderPassFormat& format) {
bool valid = true;
if (format.depth.format) {
valid &= format.depth.layout == VK_IMAGE_LAYOUT_GENERAL
|| format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|| format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|| format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
|| format.depth.layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
}
for (uint32_t i = 0; i < MaxNumRenderTargets && valid; i++) {
if (format.color[i].format) {
valid &= format.color[i].layout == VK_IMAGE_LAYOUT_GENERAL
|| format.color[i].layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
}
return valid;
}
}

View File

@ -45,8 +45,7 @@ namespace dxvk {
*/
void addGraphicsPipeline(
const DxvkStateCacheKey& shaders,
const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPassFormat& format);
const DxvkGraphicsPipelineStateInfo& state);
/**
* Adds a compute pipeline to the cache
@ -170,15 +169,6 @@ namespace dxvk {
std::string getCacheDir() const;
static uint8_t packImageLayout(
VkImageLayout layout);
static VkImageLayout unpackImageLayout(
uint8_t layout);
static bool validateRenderPassFormat(
const DxvkRenderPassFormat& format);
};
}

View File

@ -38,7 +38,6 @@ namespace dxvk {
DxvkStateCacheKey shaders;
DxvkGraphicsPipelineStateInfo gpState;
DxvkComputePipelineStateInfo cpState;
DxvkRenderPassFormat format;
Sha1Hash hash;
};
@ -52,7 +51,7 @@ namespace dxvk {
*/
struct DxvkStateCacheHeader {
char magic[4] = { 'D', 'X', 'V', 'K' };
uint32_t version = 11;
uint32_t version = 12;
uint32_t entrySize = 0; /* no longer meaningful */
};
@ -89,4 +88,39 @@ namespace dxvk {
};
/**
* \brief Old attachment format struct
*/
struct DxvkAttachmentFormatV11 {
VkFormat format = VK_FORMAT_UNDEFINED;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
};
/**
* \brief Old render pass format struct
*/
struct DxvkRenderPassFormatV11 {
VkSampleCountFlagBits sampleCount;
DxvkAttachmentFormatV11 depth;
DxvkAttachmentFormatV11 color[MaxNumRenderTargets];
DxvkRtInfo convert() const {
VkImageAspectFlags readOnlyAspects = 0;
auto depthFormatInfo = imageFormatInfo(depth.format);
if (depth.format && depthFormatInfo) {
readOnlyAspects = depthFormatInfo->aspectMask
& ~vk::getWritableAspectsForLayout(depth.layout);
}
std::array<VkFormat, MaxNumRenderTargets> colorFormats;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
colorFormats[i] = color[i].format;
return DxvkRtInfo(MaxNumRenderTargets, colorFormats.data(),
depth.format, readOnlyAspects);
}
};
}