mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-05 19:46:15 +01:00
[dxvk] Allow creating pipeline libraries with more than one shader
This commit is contained in:
parent
f9ff96d727
commit
17529101d5
@ -248,8 +248,11 @@ namespace dxvk {
|
|||||||
if (pair != m_computePipelines.end())
|
if (pair != m_computePipelines.end())
|
||||||
return &pair->second;
|
return &pair->second;
|
||||||
|
|
||||||
|
DxvkShaderPipelineLibraryKey key;
|
||||||
|
key.addShader(shaders.cs);
|
||||||
|
|
||||||
auto layout = createPipelineLayout(shaders.cs->getBindings());
|
auto layout = createPipelineLayout(shaders.cs->getBindings());
|
||||||
auto library = findPipelineLibraryLocked(shaders.cs);
|
auto library = findPipelineLibraryLocked(key);
|
||||||
|
|
||||||
auto iter = m_computePipelines.emplace(
|
auto iter = m_computePipelines.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
@ -290,9 +293,28 @@ namespace dxvk {
|
|||||||
DxvkShaderPipelineLibrary* vsLibrary = nullptr;
|
DxvkShaderPipelineLibrary* vsLibrary = nullptr;
|
||||||
DxvkShaderPipelineLibrary* fsLibrary = nullptr;
|
DxvkShaderPipelineLibrary* fsLibrary = nullptr;
|
||||||
|
|
||||||
if (shaders.tcs == nullptr && shaders.tes == nullptr && shaders.gs == nullptr) {
|
if (m_device->canUseGraphicsPipelineLibrary()) {
|
||||||
vsLibrary = findPipelineLibraryLocked(shaders.vs);
|
DxvkShaderPipelineLibraryKey vsKey;
|
||||||
fsLibrary = findPipelineLibraryLocked(shaders.fs);
|
vsKey.addShader(shaders.vs);
|
||||||
|
|
||||||
|
if (shaders.tcs != nullptr)
|
||||||
|
vsKey.addShader(shaders.tcs);
|
||||||
|
if (shaders.tes != nullptr)
|
||||||
|
vsKey.addShader(shaders.tes);
|
||||||
|
if (shaders.gs != nullptr)
|
||||||
|
vsKey.addShader(shaders.gs);
|
||||||
|
|
||||||
|
if (vsKey.canUsePipelineLibrary())
|
||||||
|
vsLibrary = findPipelineLibraryLocked(vsKey);
|
||||||
|
|
||||||
|
if (vsLibrary) {
|
||||||
|
DxvkShaderPipelineLibraryKey fsKey;
|
||||||
|
|
||||||
|
if (shaders.fs != nullptr)
|
||||||
|
fsKey.addShader(shaders.fs);
|
||||||
|
|
||||||
|
fsLibrary = findPipelineLibraryLocked(fsKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = m_graphicsPipelines.emplace(
|
auto iter = m_graphicsPipelines.emplace(
|
||||||
@ -339,7 +361,10 @@ namespace dxvk {
|
|||||||
void DxvkPipelineManager::registerShader(
|
void DxvkPipelineManager::registerShader(
|
||||||
const Rc<DxvkShader>& shader) {
|
const Rc<DxvkShader>& shader) {
|
||||||
if (canPrecompileShader(shader)) {
|
if (canPrecompileShader(shader)) {
|
||||||
auto library = createPipelineLibrary(shader);
|
DxvkShaderPipelineLibraryKey key;
|
||||||
|
key.addShader(shader);
|
||||||
|
|
||||||
|
auto library = createPipelineLibrary(key);
|
||||||
m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::Normal);
|
m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +378,10 @@ namespace dxvk {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Dispatch high-priority compile job
|
// Dispatch high-priority compile job
|
||||||
auto library = findPipelineLibrary(shader);
|
DxvkShaderPipelineLibraryKey key;
|
||||||
|
key.addShader(shader);
|
||||||
|
|
||||||
|
auto library = findPipelineLibrary(key);
|
||||||
|
|
||||||
if (library)
|
if (library)
|
||||||
m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::High);
|
m_workers.compilePipelineLibrary(library, DxvkPipelinePriority::High);
|
||||||
@ -416,46 +444,49 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibrary(
|
DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibrary(
|
||||||
const Rc<DxvkShader>& shader) {
|
const DxvkShaderPipelineLibraryKey& key) {
|
||||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||||
auto layout = createPipelineLayout(shader->getBindings());
|
return createPipelineLibraryLocked(key);
|
||||||
|
}
|
||||||
|
|
||||||
DxvkShaderPipelineLibraryKey key;
|
|
||||||
key.shader = shader;
|
DxvkShaderPipelineLibrary* DxvkPipelineManager::createPipelineLibraryLocked(
|
||||||
|
const DxvkShaderPipelineLibraryKey& key) {
|
||||||
|
auto bindings = key.getBindings();
|
||||||
|
auto layout = createPipelineLayout(bindings);
|
||||||
|
|
||||||
auto iter = m_shaderLibraries.emplace(
|
auto iter = m_shaderLibraries.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
std::tuple(key),
|
std::tuple(key),
|
||||||
std::tuple(m_device, this, shader.ptr(), layout));
|
std::tuple(m_device, this, key, layout));
|
||||||
return &iter.first->second;
|
return &iter.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* DxvkPipelineManager::createNullFsPipelineLibrary() {
|
DxvkShaderPipelineLibrary* DxvkPipelineManager::createNullFsPipelineLibrary() {
|
||||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||||
|
DxvkShaderPipelineLibraryKey key;
|
||||||
|
|
||||||
DxvkBindingLayout bindings(VK_SHADER_STAGE_FRAGMENT_BIT);
|
DxvkBindingLayout bindings(VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||||
auto layout = createPipelineLayout(bindings);
|
auto layout = createPipelineLayout(bindings);
|
||||||
|
|
||||||
auto iter = m_shaderLibraries.emplace(
|
auto iter = m_shaderLibraries.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
std::tuple(),
|
std::tuple(),
|
||||||
std::tuple(m_device, this, nullptr, layout));
|
std::tuple(m_device, this, key, layout));
|
||||||
return &iter.first->second;
|
return &iter.first->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* DxvkPipelineManager::findPipelineLibrary(
|
DxvkShaderPipelineLibrary* DxvkPipelineManager::findPipelineLibrary(
|
||||||
const Rc<DxvkShader>& shader) {
|
const DxvkShaderPipelineLibraryKey& key) {
|
||||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||||
return findPipelineLibraryLocked(shader);
|
return findPipelineLibraryLocked(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* DxvkPipelineManager::findPipelineLibraryLocked(
|
DxvkShaderPipelineLibrary* DxvkPipelineManager::findPipelineLibraryLocked(
|
||||||
const Rc<DxvkShader>& shader) {
|
const DxvkShaderPipelineLibraryKey& key) {
|
||||||
DxvkShaderPipelineLibraryKey key;
|
|
||||||
key.shader = shader;
|
|
||||||
|
|
||||||
auto pair = m_shaderLibraries.find(key);
|
auto pair = m_shaderLibraries.find(key);
|
||||||
if (pair == m_shaderLibraries.end())
|
if (pair == m_shaderLibraries.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -465,7 +496,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
bool DxvkPipelineManager::canPrecompileShader(
|
bool DxvkPipelineManager::canPrecompileShader(
|
||||||
const Rc<DxvkShader>& shader) const {
|
const Rc<DxvkShader>& shader) const {
|
||||||
if (!shader->canUsePipelineLibrary(true))
|
if (!shader->canUsePipelineLibrary(true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -295,18 +295,21 @@ namespace dxvk {
|
|||||||
const DxvkBindingLayout& layout);
|
const DxvkBindingLayout& layout);
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* createPipelineLibrary(
|
DxvkShaderPipelineLibrary* createPipelineLibrary(
|
||||||
const Rc<DxvkShader>& shader);
|
const DxvkShaderPipelineLibraryKey& key);
|
||||||
|
|
||||||
|
DxvkShaderPipelineLibrary* createPipelineLibraryLocked(
|
||||||
|
const DxvkShaderPipelineLibraryKey& key);
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* createNullFsPipelineLibrary();
|
DxvkShaderPipelineLibrary* createNullFsPipelineLibrary();
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* findPipelineLibrary(
|
DxvkShaderPipelineLibrary* findPipelineLibrary(
|
||||||
const Rc<DxvkShader>& shader);
|
const DxvkShaderPipelineLibraryKey& key);
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary* findPipelineLibraryLocked(
|
DxvkShaderPipelineLibrary* findPipelineLibraryLocked(
|
||||||
const Rc<DxvkShader>& shader);
|
const DxvkShaderPipelineLibraryKey& key);
|
||||||
|
|
||||||
bool canPrecompileShader(
|
bool canPrecompileShader(
|
||||||
const Rc<DxvkShader>& shader) const;
|
const Rc<DxvkShader>& shader) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -897,28 +897,108 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkShaderPipelineLibrary::DxvkShaderPipelineLibrary(
|
DxvkShaderPipelineLibraryKey::DxvkShaderPipelineLibraryKey() {
|
||||||
const DxvkDevice* device,
|
|
||||||
DxvkPipelineManager* manager,
|
}
|
||||||
DxvkShader* shader,
|
|
||||||
const DxvkBindingLayoutObjects* layout)
|
|
||||||
: m_device (device),
|
DxvkShaderPipelineLibraryKey::~DxvkShaderPipelineLibraryKey() {
|
||||||
m_stats (&manager->m_stats),
|
|
||||||
m_layout (layout) {
|
}
|
||||||
if (shader) {
|
|
||||||
|
|
||||||
|
DxvkShaderSet DxvkShaderPipelineLibraryKey::getShaderSet() const {
|
||||||
|
DxvkShaderSet result;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_shaderCount; i++) {
|
||||||
|
auto shader = m_shaders[i].ptr();
|
||||||
|
|
||||||
switch (shader->info().stage) {
|
switch (shader->info().stage) {
|
||||||
case VK_SHADER_STAGE_VERTEX_BIT:
|
case VK_SHADER_STAGE_VERTEX_BIT: result.vs = shader; break;
|
||||||
m_shaders.vs = shader;
|
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: result.tcs = shader; break;
|
||||||
break;
|
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: result.tes = shader; break;
|
||||||
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
case VK_SHADER_STAGE_GEOMETRY_BIT: result.gs = shader; break;
|
||||||
m_shaders.fs = shader;
|
case VK_SHADER_STAGE_FRAGMENT_BIT: result.fs = shader; break;
|
||||||
break;
|
case VK_SHADER_STAGE_COMPUTE_BIT: result.cs = shader; break;
|
||||||
case VK_SHADER_STAGE_COMPUTE_BIT:
|
|
||||||
m_shaders.cs = shader;
|
|
||||||
break;
|
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingLayout DxvkShaderPipelineLibraryKey::getBindings() const {
|
||||||
|
DxvkBindingLayout mergedLayout(m_shaderStages);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_shaderCount; i++)
|
||||||
|
mergedLayout.merge(m_shaders[i]->getBindings());
|
||||||
|
|
||||||
|
return mergedLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkShaderPipelineLibraryKey::addShader(
|
||||||
|
const Rc<DxvkShader>& shader) {
|
||||||
|
m_shaderStages |= shader->info().stage;
|
||||||
|
m_shaders[m_shaderCount++] = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkShaderPipelineLibraryKey::canUsePipelineLibrary() const {
|
||||||
|
// Ensure that each individual shader can be used in a library
|
||||||
|
bool standalone = m_shaderCount <= 1;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_shaderCount; i++) {
|
||||||
|
if (!m_shaders[i]->canUsePipelineLibrary(standalone))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that stage I/O is compatible between stages
|
||||||
|
for (uint32_t i = 0; i + 1 < m_shaderCount; i++) {
|
||||||
|
uint32_t currStageIoMask = m_shaders[i]->info().outputMask;
|
||||||
|
uint32_t nextStageIoMask = m_shaders[i + 1]->info().inputMask;
|
||||||
|
|
||||||
|
if ((currStageIoMask & nextStageIoMask) != nextStageIoMask)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkShaderPipelineLibraryKey::eq(
|
||||||
|
const DxvkShaderPipelineLibraryKey& other) const {
|
||||||
|
bool eq = m_shaderStages == other.m_shaderStages;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_shaderCount && eq; i++)
|
||||||
|
eq = m_shaders[i] == other.m_shaders[i];
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DxvkShaderPipelineLibraryKey::hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
hash.add(uint32_t(m_shaderStages));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_shaderCount; i++)
|
||||||
|
hash.add(m_shaders[i]->getHash());
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkShaderPipelineLibrary::DxvkShaderPipelineLibrary(
|
||||||
|
const DxvkDevice* device,
|
||||||
|
DxvkPipelineManager* manager,
|
||||||
|
const DxvkShaderPipelineLibraryKey& key,
|
||||||
|
const DxvkBindingLayoutObjects* layout)
|
||||||
|
: m_device (device),
|
||||||
|
m_stats (&manager->m_stats),
|
||||||
|
m_shaders (key.getShaderSet()),
|
||||||
|
m_layout (layout) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -385,22 +385,6 @@ namespace dxvk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Shader pipeline library key
|
|
||||||
*/
|
|
||||||
struct DxvkShaderPipelineLibraryKey {
|
|
||||||
Rc<DxvkShader> shader;
|
|
||||||
|
|
||||||
bool eq(const DxvkShaderPipelineLibraryKey& other) const {
|
|
||||||
return shader == other.shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t hash() const {
|
|
||||||
return DxvkShader::getHash(shader);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Shader set
|
* \brief Shader set
|
||||||
*
|
*
|
||||||
@ -433,6 +417,68 @@ namespace dxvk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Shader pipeline library key
|
||||||
|
*/
|
||||||
|
class DxvkShaderPipelineLibraryKey {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkShaderPipelineLibraryKey();
|
||||||
|
|
||||||
|
~DxvkShaderPipelineLibraryKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates shader set from key
|
||||||
|
* \returns Shader set
|
||||||
|
*/
|
||||||
|
DxvkShaderSet getShaderSet() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Generates merged binding layout
|
||||||
|
* \returns Binding layout
|
||||||
|
*/
|
||||||
|
DxvkBindingLayout getBindings() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds a shader to the key
|
||||||
|
*
|
||||||
|
* Shaders must be added in stage order.
|
||||||
|
* \param [in] shader Shader to add
|
||||||
|
*/
|
||||||
|
void addShader(
|
||||||
|
const Rc<DxvkShader>& shader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks wether a pipeline library can be created
|
||||||
|
* \returns \c true if all added shaders are compatible
|
||||||
|
*/
|
||||||
|
bool canUsePipelineLibrary() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks for equality
|
||||||
|
*
|
||||||
|
* \param [in] other Key to compare to
|
||||||
|
* \returns \c true if the keys are equal
|
||||||
|
*/
|
||||||
|
bool eq(
|
||||||
|
const DxvkShaderPipelineLibraryKey& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes key hash
|
||||||
|
* \returns Key hash
|
||||||
|
*/
|
||||||
|
size_t hash() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint32_t m_shaderCount = 0;
|
||||||
|
VkShaderStageFlags m_shaderStages = 0;
|
||||||
|
std::array<Rc<DxvkShader>, 4> m_shaders;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Shader pipeline library
|
* \brief Shader pipeline library
|
||||||
*
|
*
|
||||||
@ -449,7 +495,7 @@ namespace dxvk {
|
|||||||
DxvkShaderPipelineLibrary(
|
DxvkShaderPipelineLibrary(
|
||||||
const DxvkDevice* device,
|
const DxvkDevice* device,
|
||||||
DxvkPipelineManager* manager,
|
DxvkPipelineManager* manager,
|
||||||
DxvkShader* shader,
|
const DxvkShaderPipelineLibraryKey& key,
|
||||||
const DxvkBindingLayoutObjects* layout);
|
const DxvkBindingLayoutObjects* layout);
|
||||||
|
|
||||||
~DxvkShaderPipelineLibrary();
|
~DxvkShaderPipelineLibrary();
|
||||||
|
Loading…
Reference in New Issue
Block a user