9 #define LOC QString("VulkanShader: ")
13 #include <glslang/Public/ShaderLang.h>
14 #include <glslang/SPIRV/GlslangToSpv.h>
16 static const TBuiltInResource s_TBuiltInResource = {
123 static auto GLSLangCompile(EShLanguage Stage,
const QString &Code)
125 std::vector<uint32_t> result;
126 auto *shader =
new glslang::TShader(Stage);
130 QByteArray data = Code.toLocal8Bit();
131 const char *
tmp = data.constData();
132 shader->setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1);
133 shader->setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3);
134 shader->setStrings(&
tmp, 1);
135 if (!shader->parse(&s_TBuiltInResource, glslang::EShTargetVulkan_1_1,
true, EShMsgDefault))
137 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Shader parse error:");
138 LOG(VB_GENERAL, LOG_ERR, shader->getInfoLog());
143 auto *program =
new glslang::TProgram();
150 program->addShader(shader);
151 if (program->link(EShMsgDefault))
153 auto ByteCodeToString = [](std::vector<uint32_t> &OpCodes)
157 for (uint32_t opcode : OpCodes)
159 if (count++ == 0)
string +=
"\n";
160 if (count > 5) count = 0;
161 string +=
"0x" + QString(
"%1, ").arg(opcode, 8, 16, QLatin1Char(
'0')).toUpper();
166 glslang::SpvOptions
options { };
167 options.generateDebugInfo =
false;
170 options.disableOptimizer =
false;
172 GlslangToSpv(*program->getIntermediate(Stage), result, &
options);
173 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Generated SPIR-V: %1bytes").arg(result.size() * sizeof (uint32_t)));
174 LOG(VB_GENERAL, LOG_INFO,
"Source:\n" + Code);
175 LOG(VB_GENERAL, LOG_INFO,
"ByteCode:\n" + ByteCodeToString(result));
179 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Shader link error:");
180 LOG(VB_GENERAL, LOG_ERR, program->getInfoLog());
188 bool MythShaderVulkan::InitGLSLang(
bool Release )
190 static QMutex s_glslangLock;
191 static int s_glslangRefcount = 0;
192 static bool s_initSuccess =
false;
193 QMutexLocker locker(&s_glslangLock);
198 if (s_glslangRefcount < 0)
200 LOG(VB_GENERAL, LOG_ERR,
LOC +
"GLSLang ref count error");
204 if (s_glslangRefcount < 1)
206 LOG(VB_GENERAL, LOG_INFO,
LOC +
"GLSLang released");
207 glslang::FinalizeProcess();
212 if (s_glslangRefcount < 1)
214 s_initSuccess = glslang::InitializeProcess();
216 LOG(VB_GENERAL, LOG_INFO,
LOC +
"GLSLang initialised");
219 return s_initSuccess;
222 bool MythShaderVulkan::CreateShaderFromGLSL(
const std::vector<MythGLSLStage> &Stages)
227 if (!MythShaderVulkan::InitGLSLang())
230 std::vector<MythSPIRVStage> spirvstages;
232 auto glslangtype = [](VkShaderStageFlags Type)
236 case VK_SHADER_STAGE_VERTEX_BIT:
return EShLangVertex;
237 case VK_SHADER_STAGE_FRAGMENT_BIT:
return EShLangFragment;
238 case VK_SHADER_STAGE_COMPUTE_BIT:
return EShLangCompute;
244 for (
const auto& stage :
Stages)
245 if (glslangtype(stage.first) != EShLangCount)
246 spirvstages.emplace_back(stage.first, GLSLangCompile(glslangtype(stage.first), stage.second));
247 MythShaderVulkan::InitGLSLang(
true);
261 const std::vector<int> &Stages,
266 if (result && !result->IsValidVulkan())
268 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create shader");
276 const std::vector<int> &Stages,
292 for (
const auto & stage :
Stages)
293 if (Sources->find(stage) == Sources->end() || Bindings->find(stage) == Bindings->end())
297 bool foundvertices =
false;
298 bool pushconstants =
false;
299 VkPushConstantRange ranges = { };
301 std::map<int, std::vector<VkDescriptorSetLayoutBinding>> layoutbindings;
302 std::map<int, std::vector<VkDescriptorPoolSize>> poolsizes;
303 for (
const auto & stage :
Stages)
305 bool isvertex =
false;
310 for (
auto & stagelayout : binding)
312 if (stagelayout.second.stageFlags == VK_SHADER_STAGE_VERTEX_BIT)
315 if (layoutbindings.find(stagelayout.first) != layoutbindings.end())
316 layoutbindings.at(stagelayout.first).emplace_back(stagelayout.second);
318 layoutbindings.insert( { stagelayout.first, { stagelayout.second } } );
320 VkDescriptorPoolSize poolsize = {stagelayout.second.descriptorType, stagelayout.second.descriptorCount};
321 if (poolsizes.find(stagelayout.first) != poolsizes.end())
322 poolsizes.at(stagelayout.first).emplace_back(poolsize);
324 poolsizes.insert( { stagelayout.first, { poolsize } } );
327 if (isvertex && !foundvertices)
329 foundvertices =
true;
336 VkPushConstantRange range = std::get<4>(desc);
337 if (range.stageFlags)
339 pushconstants =
true;
346 for (
const auto& poolsize : poolsizes)
350 for (
auto & layoutbinding : layoutbindings)
353 VkDescriptorSetLayoutCreateInfo layoutinfo { };
354 layoutinfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
355 layoutinfo.bindingCount =
static_cast<uint32_t
>(layoutbinding.second.size());
356 layoutinfo.pBindings = layoutbinding.second.data();
358 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create DescriptorSetLayout");
365 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create all layouts");
369 VkPipelineLayoutCreateInfo pipelinelayout { };
370 pipelinelayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
376 pipelinelayout.pushConstantRangeCount = 1;
377 pipelinelayout.pPushConstantRanges = &ranges;
381 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create pipeline layout");
387 static bool useglsl = qEnvironmentVariableIsSet(
"MYTHTV_GLSLANG");
390 std::vector<MythGLSLStage> glslstages;
391 std::transform(
Stages.cbegin(),
Stages.cend(), std::back_inserter(glslstages),
392 [&](
int Stage) { return MythGLSLStage{Stage & VK_SHADER_STAGE_ALL_GRAPHICS, Sources->at(Stage).first }; });
393 m_vulkanValid = MythShaderVulkan::CreateShaderFromGLSL(glslstages);
398 std::vector<MythSPIRVStage> stages;
399 std::transform(Stages.cbegin(), Stages.cend(), std::back_inserter(stages),
400 [&](
int Stage) { return MythSPIRVStage{Stage & VK_SHADER_STAGE_ALL_GRAPHICS, Sources->at(Stage).second }; });
427 for (
const auto & stage :
Stages)
429 auto size = stage.second.size() *
sizeof (uint32_t);
430 auto *code =
reinterpret_cast<uint32_t*
>(
new uint8_t [size]);
431 memcpy(code, stage.second.data(), size);
433 VkShaderModuleCreateInfo create { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
nullptr, 0, size, code };
435 m_stages.push_back( { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
nullptr,
436 0,
static_cast<VkShaderStageFlagBits
>(stage.first), module,
"main",
nullptr } );
467 static const std::vector<VkDescriptorPoolSize> broken;