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:
parent
28ae85b7ab
commit
e5157a5360
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user