1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-12 13:08:50 +01:00

[dxvk] Add pre-rasterization pipeline libraries to the state cache

This allows compiling tessellation or geometry shader pipelines
early while still using the pipeline library path.

Also removes compute shaders. Since API-provided compute shaders
are always compiled early, supporting them is no longer needed.
This commit is contained in:
Philip Rebohle 2023-01-09 21:26:15 +01:00 committed by Philip Rebohle
parent 28ae85b7ab
commit e5157a5360
7 changed files with 175 additions and 119 deletions

View File

@ -60,10 +60,8 @@ namespace dxvk {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
instance = this->findInstance(state); instance = this->findInstance(state);
if (!instance) { if (!instance)
instance = this->createInstance(state); instance = this->createInstance(state);
this->writePipelineStateToCache(state);
}
} }
return instance->handle; return instance->handle;
@ -139,17 +137,6 @@ namespace dxvk {
} }
void DxvkComputePipeline::writePipelineStateToCache(
const DxvkComputePipelineStateInfo& state) const {
DxvkStateCacheKey key;
if (m_shaders.cs != nullptr)
key.cs = m_shaders.cs->getShaderKey();
m_stateCache->addComputePipeline(key, state);
}
void DxvkComputePipeline::logPipelineState( void DxvkComputePipeline::logPipelineState(
LogLevel level, LogLevel level,
const DxvkComputePipelineStateInfo& state) const { const DxvkComputePipelineStateInfo& state) const {

View File

@ -149,9 +149,6 @@ namespace dxvk {
void destroyPipeline( void destroyPipeline(
VkPipeline pipeline); VkPipeline pipeline);
void writePipelineStateToCache(
const DxvkComputePipelineStateInfo& state) const;
void logPipelineState( void logPipelineState(
LogLevel level, LogLevel level,
const DxvkComputePipelineStateInfo& state) const; const DxvkComputePipelineStateInfo& state) const;

View File

@ -297,12 +297,9 @@ namespace dxvk {
DxvkShaderPipelineLibraryKey vsKey; DxvkShaderPipelineLibraryKey vsKey;
vsKey.addShader(shaders.vs); vsKey.addShader(shaders.vs);
if (shaders.tcs != nullptr) if (shaders.tcs != nullptr) vsKey.addShader(shaders.tcs);
vsKey.addShader(shaders.tcs); if (shaders.tes != nullptr) vsKey.addShader(shaders.tes);
if (shaders.tes != nullptr) if (shaders.gs != nullptr) vsKey.addShader(shaders.gs);
vsKey.addShader(shaders.tes);
if (shaders.gs != nullptr)
vsKey.addShader(shaders.gs);
if (vsKey.canUsePipelineLibrary()) { if (vsKey.canUsePipelineLibrary()) {
vsLibrary = findPipelineLibraryLocked(vsKey); vsLibrary = findPipelineLibraryLocked(vsKey);
@ -313,6 +310,17 @@ namespace dxvk {
// Don't dispatch the pipeline library to a worker thread // Don't dispatch the pipeline library to a worker thread
// since it should be compiled on demand anyway. // since it should be compiled on demand anyway.
vsLibrary = createPipelineLibraryLocked(vsKey); vsLibrary = createPipelineLibraryLocked(vsKey);
// Register the pipeline library with the state cache
// so that subsequent runs can still compile it early
DxvkStateCacheKey shaderKeys;
shaderKeys.vs = shaders.vs->getShaderKey();
if (shaders.tcs != nullptr) shaderKeys.tcs = shaders.tcs->getShaderKey();
if (shaders.tes != nullptr) shaderKeys.tes = shaders.tes->getShaderKey();
if (shaders.gs != nullptr) shaderKeys.gs = shaders.gs->getShaderKey();
m_stateCache.addPipelineLibrary(shaderKeys);
} }
} }
@ -335,6 +343,13 @@ namespace dxvk {
} }
DxvkShaderPipelineLibrary* DxvkPipelineManager::createShaderPipelineLibrary(
const DxvkShaderPipelineLibraryKey& key) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
return createPipelineLibraryLocked(key);
}
DxvkGraphicsPipelineVertexInputLibrary* DxvkPipelineManager::createVertexInputLibrary( DxvkGraphicsPipelineVertexInputLibrary* DxvkPipelineManager::createVertexInputLibrary(
const DxvkGraphicsPipelineVertexInputState& state) { const DxvkGraphicsPipelineVertexInputState& state) {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
@ -373,7 +388,7 @@ namespace dxvk {
DxvkShaderPipelineLibraryKey key; DxvkShaderPipelineLibraryKey key;
key.addShader(shader); key.addShader(shader);
auto library = createPipelineLibrary(key); auto library = createShaderPipelineLibrary(key);
m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::Normal); m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::Normal);
} }
@ -452,13 +467,6 @@ namespace dxvk {
} }
DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibrary(
const DxvkShaderPipelineLibraryKey& key) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
return createPipelineLibraryLocked(key);
}
DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibraryLocked( DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibraryLocked(
const DxvkShaderPipelineLibraryKey& key) { const DxvkShaderPipelineLibraryKey& key) {
auto bindings = key.getBindings(); auto bindings = key.getBindings();

View File

@ -185,6 +185,16 @@ namespace dxvk {
DxvkGraphicsPipeline* createGraphicsPipeline( DxvkGraphicsPipeline* createGraphicsPipeline(
const DxvkGraphicsPipelineShaders& shaders); const DxvkGraphicsPipelineShaders& shaders);
/**
* \brief Creates a pipeline library with a given set of shaders
*
* If a pipeline library already exists, it will be returned.
* Otherwise, a new pipeline library will be created.
* \param [in] key Shader set
*/
DxvkShaderPipelineLibrary* createShaderPipelineLibrary(
const DxvkShaderPipelineLibraryKey& key);
/** /**
* \brief Retrieves a vertex input pipeline library * \brief Retrieves a vertex input pipeline library
* *
@ -294,9 +304,6 @@ namespace dxvk {
DxvkBindingLayoutObjects* createPipelineLayout( DxvkBindingLayoutObjects* createPipelineLayout(
const DxvkBindingLayout& layout); const DxvkBindingLayout& layout);
DxvkShaderPipelineLibrary* createPipelineLibrary(
const DxvkShaderPipelineLibraryKey& key);
DxvkShaderPipelineLibrary* createPipelineLibraryLocked( DxvkShaderPipelineLibrary* createPipelineLibraryLocked(
const DxvkShaderPipelineLibraryKey& key); const DxvkShaderPipelineLibraryKey& key);

View File

@ -12,6 +12,16 @@ namespace dxvk {
* \brief Packed entry header * \brief Packed entry header
*/ */
struct DxvkStateCacheEntryHeader { struct DxvkStateCacheEntryHeader {
uint32_t entryType : 1;
uint32_t stageMask : 5;
uint32_t entrySize : 26;
};
/**
* \brief Version 8 entry header
*/
struct DxvkStateCacheEntryHeaderV8 {
uint32_t stageMask : 8; uint32_t stageMask : 8;
uint32_t entrySize : 24; uint32_t entrySize : 24;
}; };
@ -44,6 +54,28 @@ namespace dxvk {
return read(data); return read(data);
} }
bool read(DxvkStateCacheKey& shaders, uint32_t version, VkShaderStageFlags stageFlags) {
DxvkShaderKey dummyKey;
std::array<std::pair<VkShaderStageFlagBits, DxvkShaderKey*>, 6> stages = {{
{ VK_SHADER_STAGE_VERTEX_BIT, &shaders.vs },
{ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, &shaders.tcs },
{ VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, &shaders.tes },
{ VK_SHADER_STAGE_GEOMETRY_BIT, &shaders.gs },
{ VK_SHADER_STAGE_FRAGMENT_BIT, &shaders.fs },
{ VK_SHADER_STAGE_COMPUTE_BIT, &dummyKey },
}};
for (uint32_t i = 0; i < stages.size(); i++) {
if (stageFlags & stages[i].first) {
if (!read(*stages[i].second, version))
return false;
}
}
return true;
}
bool read(DxvkBindingMaskV10& data, uint32_t version) { bool read(DxvkBindingMaskV10& data, uint32_t version) {
// v11 removes this field // v11 removes this field
if (version >= 11) if (version >= 11)
@ -208,8 +240,7 @@ namespace dxvk {
&& this->tcs.eq(key.tcs) && this->tcs.eq(key.tcs)
&& this->tes.eq(key.tes) && this->tes.eq(key.tes)
&& this->gs.eq(key.gs) && this->gs.eq(key.gs)
&& this->fs.eq(key.fs) && this->fs.eq(key.fs);
&& this->cs.eq(key.cs);
} }
@ -220,7 +251,6 @@ namespace dxvk {
hash.add(this->tes.hash()); hash.add(this->tes.hash());
hash.add(this->gs.hash()); hash.add(this->gs.hash());
hash.add(this->fs.hash()); hash.add(this->fs.hash());
hash.add(this->cs.hash());
return hash; return hash;
} }
@ -257,52 +287,52 @@ namespace dxvk {
} }
void DxvkStateCache::addGraphicsPipeline( void DxvkStateCache::addPipelineLibrary(
const DxvkStateCacheKey& shaders, const DxvkStateCacheKey& shaders) {
const DxvkGraphicsPipelineStateInfo& state) {
if (!m_enable || shaders.vs.eq(g_nullShaderKey)) if (!m_enable || shaders.vs.eq(g_nullShaderKey))
return; return;
// Do not add an entry that is already in the cache // Do not add an entry that is already in the cache
auto entries = m_entryMap.equal_range(shaders); auto entries = m_entryMap.equal_range(shaders);
for (auto e = entries.first; e != entries.second; e++) { for (auto e = entries.first; e != entries.second; e++) {
const DxvkStateCacheEntry& entry = m_entries[e->second]; if (m_entries[e->second].type == DxvkStateCacheEntryType::PipelineLibrary)
if (entry.gpState == state)
return; return;
} }
// Queue a job to write this pipeline to the cache // Queue a job to write this pipeline to the cache
std::unique_lock<dxvk::mutex> lock(m_writerLock); std::unique_lock<dxvk::mutex> lock(m_writerLock);
m_writerQueue.push({ shaders, state, m_writerQueue.push({
DxvkComputePipelineStateInfo(), g_nullHash }); DxvkStateCacheEntryType::PipelineLibrary, shaders,
DxvkGraphicsPipelineStateInfo(), g_nullHash });
m_writerCond.notify_one(); m_writerCond.notify_one();
createWriter(); createWriter();
} }
void DxvkStateCache::addComputePipeline( void DxvkStateCache::addGraphicsPipeline(
const DxvkStateCacheKey& shaders, const DxvkStateCacheKey& shaders,
const DxvkComputePipelineStateInfo& state) { const DxvkGraphicsPipelineStateInfo& state) {
if (!m_enable || shaders.cs.eq(g_nullShaderKey)) if (!m_enable || shaders.vs.eq(g_nullShaderKey))
return; return;
// Do not add an entry that is already in the cache // Do not add an entry that is already in the cache
auto entries = m_entryMap.equal_range(shaders); auto entries = m_entryMap.equal_range(shaders);
for (auto e = entries.first; e != entries.second; e++) { for (auto e = entries.first; e != entries.second; e++) {
if (m_entries[e->second].cpState == state) if (m_entries[e->second].type == DxvkStateCacheEntryType::MonolithicPipeline
&& m_entries[e->second].gpState == state)
return; return;
} }
// Queue a job to write this pipeline to the cache // Queue a job to write this pipeline to the cache
std::unique_lock<dxvk::mutex> lock(m_writerLock); std::unique_lock<dxvk::mutex> lock(m_writerLock);
m_writerQueue.push({ shaders, m_writerQueue.push({
DxvkGraphicsPipelineStateInfo(), state, g_nullHash }); DxvkStateCacheEntryType::MonolithicPipeline,
shaders, state, g_nullHash });
m_writerCond.notify_one(); m_writerCond.notify_one();
createWriter(); createWriter();
@ -334,8 +364,7 @@ namespace dxvk {
|| !getShaderByKey(p->second.tcs, item.gp.tcs) || !getShaderByKey(p->second.tcs, item.gp.tcs)
|| !getShaderByKey(p->second.tes, item.gp.tes) || !getShaderByKey(p->second.tes, item.gp.tes)
|| !getShaderByKey(p->second.gs, item.gp.gs) || !getShaderByKey(p->second.gs, item.gp.gs)
|| !getShaderByKey(p->second.fs, item.gp.fs) || !getShaderByKey(p->second.fs, item.gp.fs))
|| !getShaderByKey(p->second.cs, item.cp.cs))
continue; continue;
if (!workerLock) if (!workerLock)
@ -412,23 +441,35 @@ namespace dxvk {
key.tes = getShaderKey(item.gp.tes); key.tes = getShaderKey(item.gp.tes);
key.gs = getShaderKey(item.gp.gs); key.gs = getShaderKey(item.gp.gs);
key.fs = getShaderKey(item.gp.fs); key.fs = getShaderKey(item.gp.fs);
key.cs = getShaderKey(item.cp.cs);
if (item.cp.cs == nullptr) { DxvkGraphicsPipeline* pipeline = nullptr;
auto pipeline = m_pipeManager->createGraphicsPipeline(item.gp); auto entries = m_entryMap.equal_range(key);
auto entries = m_entryMap.equal_range(key);
for (auto e = entries.first; e != entries.second; e++) { for (auto e = entries.first; e != entries.second; e++) {
const auto& entry = m_entries[e->second]; const auto& entry = m_entries[e->second];
m_pipeWorkers->compileGraphicsPipeline(pipeline, entry.gpState);
}
} else {
auto pipeline = m_pipeManager->createComputePipeline(item.cp);
auto entries = m_entryMap.equal_range(key);
for (auto e = entries.first; e != entries.second; e++) { switch (entry.type) {
const auto& entry = m_entries[e->second]; case DxvkStateCacheEntryType::MonolithicPipeline: {
m_pipeWorkers->compileComputePipeline(pipeline, entry.cpState); if (!pipeline)
pipeline = m_pipeManager->createGraphicsPipeline(item.gp);
m_pipeWorkers->compileGraphicsPipeline(pipeline, entry.gpState);
} break;
case DxvkStateCacheEntryType::PipelineLibrary: {
if (!m_device->canUseGraphicsPipelineLibrary() || item.gp.vs == nullptr)
break;
DxvkShaderPipelineLibraryKey libraryKey;
libraryKey.addShader(item.gp.vs);
if (item.gp.tcs != nullptr) libraryKey.addShader(item.gp.tcs);
if (item.gp.tes != nullptr) libraryKey.addShader(item.gp.tes);
if (item.gp.gs != nullptr) libraryKey.addShader(item.gp.gs);
auto pipelineLibrary = m_pipeManager->createShaderPipelineLibrary(libraryKey);
m_pipeWorkers->compilePipelineLibrary(pipelineLibrary, DxvkPipelinePriority::Normal);
} break;
} }
} }
} }
@ -483,7 +524,6 @@ namespace dxvk {
mapShaderToPipeline(entry.shaders.tes, entry.shaders); mapShaderToPipeline(entry.shaders.tes, entry.shaders);
mapShaderToPipeline(entry.shaders.gs, entry.shaders); mapShaderToPipeline(entry.shaders.gs, entry.shaders);
mapShaderToPipeline(entry.shaders.fs, entry.shaders); mapShaderToPipeline(entry.shaders.fs, entry.shaders);
mapShaderToPipeline(entry.shaders.cs, entry.shaders);
} else if (ifile) { } else if (ifile) {
numInvalidEntries += 1; numInvalidEntries += 1;
} }
@ -531,11 +571,28 @@ namespace dxvk {
DxvkStateCacheEntry& entry) const { DxvkStateCacheEntry& entry) const {
// Read entry metadata and actual data // Read entry metadata and actual data
DxvkStateCacheEntryHeader header; DxvkStateCacheEntryHeader header;
DxvkStateCacheEntryHeaderV8 headerV8;
DxvkStateCacheEntryData data; DxvkStateCacheEntryData data;
VkShaderStageFlags stageMask;
Sha1Hash hash; Sha1Hash hash;
if (!stream.read(reinterpret_cast<char*>(&header), sizeof(header)) if (version >= 16) {
|| !stream.read(reinterpret_cast<char*>(&hash), sizeof(hash)) if (!stream.read(reinterpret_cast<char*>(&header), sizeof(header)))
return false;
stageMask = VkShaderStageFlags(header.stageMask);
} else {
if (!stream.read(reinterpret_cast<char*>(&headerV8), sizeof(headerV8)))
return false;
header.entryType = uint32_t(DxvkStateCacheEntryType::MonolithicPipeline);
header.stageMask = headerV8.stageMask & VK_SHADER_STAGE_ALL_GRAPHICS;
header.entrySize = headerV8.entrySize;
stageMask = VkShaderStageFlags(headerV8.stageMask);
}
if (!stream.read(reinterpret_cast<char*>(&hash), sizeof(hash))
|| !data.readFromStream(stream, header.entrySize)) || !data.readFromStream(stream, header.entrySize))
return false; return false;
@ -543,16 +600,15 @@ namespace dxvk {
if (hash != data.computeHash()) if (hash != data.computeHash())
return false; return false;
// Read shader hashes // Set up entry metadata
VkShaderStageFlags stageMask = VkShaderStageFlags(header.stageMask); entry.type = DxvkStateCacheEntryType(header.entryType);
auto keys = &entry.shaders.vs;
for (uint32_t i = 0; i < 6; i++) { // Read shader hashes
if (stageMask & VkShaderStageFlagBits(1 << i)) auto entryType = DxvkStateCacheEntryType(header.entryType);
data.read(keys[i], version); data.read(entry.shaders, version, stageMask);
else
keys[i] = g_nullShaderKey; if (entryType == DxvkStateCacheEntryType::PipelineLibrary)
} return true;
DxvkBindingMaskV10 dummyBindingMask = { }; DxvkBindingMaskV10 dummyBindingMask = { };
@ -610,10 +666,6 @@ namespace dxvk {
} }
// Read non-zero spec constants // Read non-zero spec constants
auto& sc = (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
? entry.cpState.sc
: entry.gpState.sc;
uint32_t specConstantMask = 0; uint32_t specConstantMask = 0;
if (!data.read(specConstantMask, version)) if (!data.read(specConstantMask, version))
@ -621,11 +673,15 @@ namespace dxvk {
for (uint32_t i = 0; i < MaxNumSpecConstants; i++) { for (uint32_t i = 0; i < MaxNumSpecConstants; i++) {
if (specConstantMask & (1 << i)) { if (specConstantMask & (1 << i)) {
if (!data.read(sc.specConstants[i], version)) if (!data.read(entry.gpState.sc.specConstants[i], version))
return false; return false;
} }
} }
// Compute shaders are no longer supported
if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
return false;
return true; return true;
} }
@ -646,7 +702,7 @@ namespace dxvk {
} }
} }
if (!(stageMask & VK_SHADER_STAGE_COMPUTE_BIT)) { if (entry.type != DxvkStateCacheEntryType::PipelineLibrary) {
// Write out common pipeline state // Write out common pipeline state
data.write(entry.gpState.ia); data.write(entry.gpState.ia);
data.write(entry.gpState.il); data.write(entry.gpState.il);
@ -671,28 +727,25 @@ namespace dxvk {
for (uint32_t i = 0; i < entry.gpState.il.bindingCount(); i++) for (uint32_t i = 0; i < entry.gpState.il.bindingCount(); i++)
data.write(entry.gpState.ilBindings[i]); data.write(entry.gpState.ilBindings[i]);
}
// Write out all non-zero spec constants // Write out all non-zero spec constants
auto& sc = (stageMask & VK_SHADER_STAGE_COMPUTE_BIT) uint32_t specConstantMask = 0;
? entry.cpState.sc
: entry.gpState.sc;
uint32_t specConstantMask = 0; for (uint32_t i = 0; i < MaxNumSpecConstants; i++)
specConstantMask |= entry.gpState.sc.specConstants[i] ? (1 << i) : 0;
for (uint32_t i = 0; i < MaxNumSpecConstants; i++) data.write(specConstantMask);
specConstantMask |= sc.specConstants[i] ? (1 << i) : 0;
data.write(specConstantMask); for (uint32_t i = 0; i < MaxNumSpecConstants; i++) {
if (specConstantMask & (1 << i))
for (uint32_t i = 0; i < MaxNumSpecConstants; i++) { data.write(entry.gpState.sc.specConstants[i]);
if (specConstantMask & (1 << i)) }
data.write(sc.specConstants[i]);
} }
// General layout: header -> hash -> data // General layout: header -> hash -> data
DxvkStateCacheEntryHeader header; DxvkStateCacheEntryHeader header;
header.stageMask = uint8_t(stageMask); header.entryType = uint32_t(entry.type);
header.stageMask = uint32_t(stageMask);
header.entrySize = data.size(); header.entrySize = data.size();
Sha1Hash hash = data.computeHash(); Sha1Hash hash = data.computeHash();

View File

@ -37,30 +37,27 @@ namespace dxvk {
~DxvkStateCache(); ~DxvkStateCache();
/** /**
* Adds a graphics pipeline to the cache * \brief Adds pipeline library to the cache
*
* If the pipeline is not already cached, this
* will write a new pipeline to the cache file.
* \param [in] shaders Shader keys
*/
void addPipelineLibrary(
const DxvkStateCacheKey& shaders);
/**
* \brief Adds a graphics pipeline to the cache
* *
* If the pipeline is not already cached, this * If the pipeline is not already cached, this
* will write a new pipeline to the cache file. * will write a new pipeline to the cache file.
* \param [in] shaders Shader keys * \param [in] shaders Shader keys
* \param [in] state Graphics pipeline state * \param [in] state Graphics pipeline state
* \param [in] format Render pass format
*/ */
void addGraphicsPipeline( void addGraphicsPipeline(
const DxvkStateCacheKey& shaders, const DxvkStateCacheKey& shaders,
const DxvkGraphicsPipelineStateInfo& state); const DxvkGraphicsPipelineStateInfo& state);
/**
* Adds a compute pipeline to the cache
*
* If the pipeline is not already cached, this
* will write a new pipeline to the cache file.
* \param [in] shaders Shader keys
* \param [in] state Compute pipeline state
*/
void addComputePipeline(
const DxvkStateCacheKey& shaders,
const DxvkComputePipelineStateInfo& state);
/** /**
* \brief Registers a newly compiled shader * \brief Registers a newly compiled shader
* *
@ -83,7 +80,6 @@ namespace dxvk {
struct WorkerItem { struct WorkerItem {
DxvkGraphicsPipelineShaders gp; DxvkGraphicsPipelineShaders gp;
DxvkComputePipelineShaders cp;
}; };
DxvkDevice* m_device; DxvkDevice* m_device;

View File

@ -19,13 +19,21 @@ namespace dxvk {
DxvkShaderKey tes; DxvkShaderKey tes;
DxvkShaderKey gs; DxvkShaderKey gs;
DxvkShaderKey fs; DxvkShaderKey fs;
DxvkShaderKey cs;
bool eq(const DxvkStateCacheKey& key) const; bool eq(const DxvkStateCacheKey& key) const;
size_t hash() const; size_t hash() const;
}; };
/**
* \brief State entry type
*/
enum class DxvkStateCacheEntryType : uint32_t {
MonolithicPipeline = 0,
PipelineLibrary = 1,
};
/** /**
* \brief State entry * \brief State entry
@ -36,9 +44,9 @@ namespace dxvk {
* that is used as a check sum to verify integrity. * that is used as a check sum to verify integrity.
*/ */
struct DxvkStateCacheEntry { struct DxvkStateCacheEntry {
DxvkStateCacheEntryType type;
DxvkStateCacheKey shaders; DxvkStateCacheKey shaders;
DxvkGraphicsPipelineStateInfo gpState; DxvkGraphicsPipelineStateInfo gpState;
DxvkComputePipelineStateInfo cpState;
Sha1Hash hash; Sha1Hash hash;
}; };
@ -52,7 +60,7 @@ namespace dxvk {
*/ */
struct DxvkStateCacheHeader { struct DxvkStateCacheHeader {
char magic[4] = { 'D', 'X', 'V', 'K' }; char magic[4] = { 'D', 'X', 'V', 'K' };
uint32_t version = 15; uint32_t version = 16;
uint32_t entrySize = 0; /* no longer meaningful */ uint32_t entrySize = 0; /* no longer meaningful */
}; };