2#include "libmythbase/mythconfig.h"
10#define LOC QString("VulkanShader: ")
14#include <glslang/Public/ShaderLang.h>
15#include <glslang/SPIRV/GlslangToSpv.h>
17static const TBuiltInResource s_TBuiltInResource = {
124static auto GLSLangCompile(EShLanguage Stage,
const QString &Code)
126 std::vector<uint32_t> result;
127 auto *shader =
new glslang::TShader(Stage);
131 QByteArray data = Code.toLocal8Bit();
132 const char *tmp = data.constData();
133 shader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
134 shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
135 shader->setStrings(&tmp, 1);
136 if (!shader->parse(&s_TBuiltInResource, glslang::EShTargetVulkan_1_1,
true, EShMsgDefault))
138 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Shader parse error:");
139 LOG(VB_GENERAL, LOG_ERR, shader->getInfoLog());
144 auto *program =
new glslang::TProgram();
151 program->addShader(shader);
152 if (program->link(EShMsgDefault))
154 auto ByteCodeToString = [](std::vector<uint32_t> &OpCodes)
158 for (uint32_t opcode : OpCodes)
160 if (count++ == 0)
string +=
"\n";
161 if (count > 5) count = 0;
162 string +=
"0x" + QString(
"%1, ").arg(opcode, 8, 16, QLatin1Char(
'0')).toUpper();
167 glslang::SpvOptions
options { };
168 options.generateDebugInfo =
false;
171 options.disableOptimizer =
false;
173 GlslangToSpv(*program->getIntermediate(Stage), result, &
options);
174 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Generated SPIR-V: %1bytes").arg(result.size() * sizeof (uint32_t)));
175 LOG(VB_GENERAL, LOG_INFO,
"Source:\n" + Code);
176 LOG(VB_GENERAL, LOG_INFO,
"ByteCode:\n" + ByteCodeToString(result));
180 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Shader link error:");
181 LOG(VB_GENERAL, LOG_ERR, program->getInfoLog());
189bool MythShaderVulkan::InitGLSLang(
bool Release )
191 static QMutex s_glslangLock;
192 static int s_glslangRefcount = 0;
193 static bool s_initSuccess =
false;
194 QMutexLocker locker(&s_glslangLock);
199 if (s_glslangRefcount < 0)
201 LOG(VB_GENERAL, LOG_ERR,
LOC +
"GLSLang ref count error");
205 if (s_glslangRefcount < 1)
207 LOG(VB_GENERAL, LOG_INFO,
LOC +
"GLSLang released");
208 glslang::FinalizeProcess();
213 if (s_glslangRefcount < 1)
215 s_initSuccess = glslang::InitializeProcess();
217 LOG(VB_GENERAL, LOG_INFO,
LOC +
"GLSLang initialised");
220 return s_initSuccess;
223bool MythShaderVulkan::CreateShaderFromGLSL(
const std::vector<MythGLSLStage> &Stages)
228 if (!MythShaderVulkan::InitGLSLang())
231 std::vector<MythSPIRVStage> spirvstages;
233 auto glslangtype = [](VkShaderStageFlags Type)
237 case VK_SHADER_STAGE_VERTEX_BIT:
return EShLangVertex;
238 case VK_SHADER_STAGE_FRAGMENT_BIT:
return EShLangFragment;
239 case VK_SHADER_STAGE_COMPUTE_BIT:
return EShLangCompute;
245 for (
const auto& stage :
Stages)
246 if (glslangtype(stage.first) != EShLangCount)
247 spirvstages.emplace_back(stage.first, GLSLangCompile(glslangtype(stage.first), stage.second));
248 MythShaderVulkan::InitGLSLang(
true);
262 const std::vector<int> &Stages,
267 if (result && !result->IsValidVulkan())
269 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create shader");
277 const std::vector<int> &Stages,
293 for (
const auto & stage :
Stages)
294 if (Sources->find(stage) == Sources->end() || Bindings->find(stage) == Bindings->end())
298 bool foundvertices =
false;
299 bool pushconstants =
false;
300 VkPushConstantRange ranges = { };
302 std::map<int, std::vector<VkDescriptorSetLayoutBinding>> layoutbindings;
303 std::map<int, std::vector<VkDescriptorPoolSize>> poolsizes;
304 for (
const auto & stage :
Stages)
306 bool isvertex =
false;
311 for (
auto & stagelayout : binding)
313 if (stagelayout.second.stageFlags == VK_SHADER_STAGE_VERTEX_BIT)
316 if (layoutbindings.find(stagelayout.first) != layoutbindings.end())
317 layoutbindings.at(stagelayout.first).emplace_back(stagelayout.second);
319 layoutbindings.insert( { stagelayout.first, { stagelayout.second } } );
321 VkDescriptorPoolSize poolsize = {stagelayout.second.descriptorType, stagelayout.second.descriptorCount};
322 if (poolsizes.find(stagelayout.first) != poolsizes.end())
323 poolsizes.at(stagelayout.first).emplace_back(poolsize);
325 poolsizes.insert( { stagelayout.first, { poolsize } } );
328 if (isvertex && !foundvertices)
330 foundvertices =
true;
337 VkPushConstantRange range = std::get<4>(desc);
338 if (range.stageFlags)
340 pushconstants =
true;
347 for (
const auto& poolsize : poolsizes)
351 for (
auto & layoutbinding : layoutbindings)
354 VkDescriptorSetLayoutCreateInfo layoutinfo { };
355 layoutinfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
356 layoutinfo.bindingCount =
static_cast<uint32_t
>(layoutbinding.second.size());
357 layoutinfo.pBindings = layoutbinding.second.data();
359 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create DescriptorSetLayout");
366 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create all layouts");
370 VkPipelineLayoutCreateInfo pipelinelayout { };
371 pipelinelayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
377 pipelinelayout.pushConstantRangeCount = 1;
378 pipelinelayout.pPushConstantRanges = &ranges;
382 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create pipeline layout");
388 static bool useglsl = qEnvironmentVariableIsSet(
"MYTHTV_GLSLANG");
391 std::vector<MythGLSLStage> glslstages;
392 std::transform(
Stages.cbegin(),
Stages.cend(), std::back_inserter(glslstages),
393 [&](
int Stage) { return MythGLSLStage{Stage & VK_SHADER_STAGE_ALL_GRAPHICS, Sources->at(Stage).first }; });
394 m_vulkanValid = MythShaderVulkan::CreateShaderFromGLSL(glslstages);
399 std::vector<MythSPIRVStage> stages;
400 std::transform(Stages.cbegin(), Stages.cend(), std::back_inserter(stages),
401 [&](
int Stage) { return MythSPIRVStage{Stage & VK_SHADER_STAGE_ALL_GRAPHICS, Sources->at(Stage).second }; });
428 for (
const auto & stage :
Stages)
430 auto size = stage.second.size() *
sizeof (uint32_t);
431 auto *code =
reinterpret_cast<uint32_t*
>(
new uint8_t [size]);
432 memcpy(code, stage.second.data(), size);
434 VkShaderModuleCreateInfo create { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
nullptr, 0, size, code };
436 m_stages.push_back( { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
nullptr,
437 0,
static_cast<VkShaderStageFlagBits
>(stage.first), module,
"main",
nullptr } );
468 static const std::vector<VkDescriptorPoolSize> broken;
Creates shader objects suitable for use with the Vulkan API.
VkPrimitiveTopology GetTopology() const
std::vector< uint32_t * > m_spirv
const std::vector< VkDescriptorPoolSize > & GetPoolSizes(size_t Set) const
bool CreateShaderFromSPIRV(const std::vector< MythSPIRVStage > &Stages)
const std::vector< VkPipelineShaderStageCreateInfo > & Stages(void) const
VkVertexInputBindingDescription m_vertexBindingDesc
VkPipelineLayout m_pipelineLayout
std::vector< std::vector< VkDescriptorPoolSize > > m_descriptorPoolSizes
MythShaderVulkan(MythVulkanObject *Vulkan, const std::vector< int > &Stages, const MythShaderMap *Sources=nullptr, const MythBindingMap *Bindings=nullptr)
VkDescriptorSetLayout GetDescSetLayout(size_t Set) const
static MythShaderVulkan * Create(MythVulkanObject *Vulkan, const std::vector< int > &Stages, const MythShaderMap *Sources=nullptr, const MythBindingMap *Bindings=nullptr)
MythVertexAttrs m_vertexAttributes
VkPrimitiveTopology m_topology
const VkVertexInputBindingDescription & GetVertexBindingDesc(void) const
const MythVertexAttrs & GetVertexAttributes(void) const
std::vector< VkPipelineShaderStageCreateInfo > m_stages
std::vector< VkDescriptorSetLayout > m_descriptorSetLayouts
VkPipelineLayout GetPipelineLayout(void) const
QVulkanDeviceFunctions * m_vulkanFuncs
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
#define MYTH_NULL_DISPATCH
static const MythBindingMap k450ShaderBindings
static const MythShaderMap k450DefaultShaders
std::pair< VkShaderStageFlags, const std::vector< uint32_t > > MythSPIRVStage
std::map< int, std::pair< QString, std::vector< uint32_t > > > MythShaderMap
std::vector< VkVertexInputAttributeDescription > MythVertexAttrs
std::tuple< VkPrimitiveTopology, MythStageLayout, VkVertexInputBindingDescription, MythVertexAttrs, VkPushConstantRange > MythBindingDesc
std::vector< MythSetLayout > MythStageLayout
std::map< int, MythBindingDesc > MythBindingMap