Files
Seele/src/Engine/Graphics/Shader.cpp
T

169 lines
6.5 KiB
C++

#include "Shader.h"
#include "Graphics/Graphics.h"
#include "Graphics/Initializer.h"
#include "Material/Material.h"
#include "ThreadPool.h"
#include <fmt/core.h>
using namespace Seele;
using namespace Seele::Gfx;
ShaderCompiler::ShaderCompiler(Gfx::PGraphics graphics) : graphics(graphics) {}
ShaderCompiler::~ShaderCompiler() {}
const ShaderCollection* ShaderCompiler::findShaders(PermutationId id) const { return &shaders[id]; }
void ShaderCompiler::registerMaterial(PMaterial material) {
materials[material->getName()] = material;
compile();
}
void ShaderCompiler::registerVertexData(VertexData* vd) {
vertexData[vd->getTypeName()] = vd;
compile();
}
void ShaderCompiler::registerRenderPass(std::string name, PassConfig config) {
passes[name] = std::move(config);
compile();
}
ShaderPermutation ShaderCompiler::getTemplate(std::string name) {
std::scoped_lock lock(shadersLock);
ShaderPermutation permutation;
PassConfig& pass = passes[name];
if (pass.useMeshShading) {
permutation.setMeshFile(pass.mainFile);
} else if (pass.rayTracing) {
permutation.setRayTracingFile(pass.mainFile);
} else {
permutation.setVertexFile(pass.mainFile);
}
if (pass.hasFragmentShader) {
permutation.setFragmentFile(pass.fragmentFile);
}
if (pass.hasTaskShader) {
permutation.setTaskFile(pass.taskFile);
}
permutation.setVisibilityPass(pass.useVisibility);
permutation.setDumpIntermediates(pass.dumpIntermediates);
return permutation;
}
void ShaderCompiler::compile() {
List<std::function<void()>> work;
for (const auto& [name, pass] : passes) {
for (const auto& [vdName, vd] : vertexData) {
if (pass.useMaterial) {
for (const auto& [matName, mat] : materials) {
for (int y = 0; y < 2; y++) {
work.add([=]() {
ShaderPermutation permutation = getTemplate(name);
permutation.setPositionOnly(false);
permutation.setDepthCulling(y);
permutation.setVertexData(vd->getTypeName());
OPipelineLayout layout = graphics->createPipelineLayout(pass.baseLayout->getName(), pass.baseLayout);
layout->addDescriptorLayout(vd->getVertexDataLayout());
layout->addDescriptorLayout(vd->getInstanceDataLayout());
permutation.setMaterial(mat->getName());
createShaders(permutation, std::move(layout));
});
}
}
} else {
for (int x = 0; x < 2; x++) {
for (int y = 0; y < 2; y++) {
work.add([=]() {
ShaderPermutation permutation = getTemplate(name);
permutation.setPositionOnly(x);
permutation.setDepthCulling(y);
permutation.setVertexData(vd->getTypeName());
OPipelineLayout layout = graphics->createPipelineLayout(pass.baseLayout->getName(), pass.baseLayout);
layout->addDescriptorLayout(vd->getVertexDataLayout());
layout->addDescriptorLayout(vd->getInstanceDataLayout());
createShaders(permutation, std::move(layout));
});
}
}
}
}
}
getThreadPool().runAndWait(std::move(work));
}
void ShaderCompiler::createShaders(ShaderPermutation permutation, Gfx::OPipelineLayout layout) {
PermutationId perm = PermutationId(permutation);
{
std::scoped_lock lock(shadersLock);
if (shaders.contains(perm))
return;
}
ShaderCollection collection;
collection.pipelineLayout = std::move(layout);
ShaderCompilationInfo createInfo;
createInfo.name = fmt::format("Material {0}", permutation.materialName);
createInfo.rootSignature = collection.pipelineLayout;
if (std::strlen(permutation.materialName) > 0) {
createInfo.modules.add(permutation.materialName);
createInfo.defines["MATERIAL_FILE_NAME"] = permutation.materialName;
}
if (permutation.positionOnly) {
createInfo.defines["POS_ONLY"] = "1";
}
if (permutation.depthCulling) {
createInfo.defines["DEPTH_CULLING"] = "1";
}
if (permutation.visibilityPass) {
createInfo.defines["VISIBILITY"] = "1";
}
if (permutation.dumpIntermediates)
{
createInfo.dumpIntermediate = true;
}
createInfo.typeParameter.add({Pair<const char*, const char*>("IVertexData", permutation.vertexDataName)});
createInfo.modules.add(permutation.vertexDataName);
if (permutation.useMeshShading) {
if (permutation.hasTaskShader) {
createInfo.entryPoints.add({"taskMain", permutation.taskFile});
createInfo.modules.add(permutation.taskFile);
}
createInfo.entryPoints.add({"meshMain", permutation.vertexMeshFile});
createInfo.modules.add(permutation.vertexMeshFile);
} else if (permutation.rayTracing) {
createInfo.defines["RAY_TRACING"] = "1";
createInfo.entryPoints = {{"closestHit", "ClosestHit"}};
createInfo.modules.add(permutation.vertexMeshFile);
} else {
createInfo.entryPoints.add({"vertexMain", permutation.vertexMeshFile});
createInfo.modules.add(permutation.vertexMeshFile);
}
if (permutation.hasFragment) {
createInfo.entryPoints.add({"fragmentMain", permutation.fragmentFile});
createInfo.modules.add(permutation.fragmentFile);
}
graphics->beginShaderCompilation(createInfo);
uint32 shaderIndex = 0;
if (permutation.useMeshShading) {
if (permutation.hasTaskShader) {
collection.taskShader = graphics->createTaskShader({shaderIndex++});
}
collection.meshShader = graphics->createMeshShader({shaderIndex++});
} else if (permutation.rayTracing) {
collection.callableShader = graphics->createClosestHitShader({shaderIndex++});
} else {
collection.vertexShader = graphics->createVertexShader({shaderIndex++});
}
if (permutation.hasFragment) {
collection.fragmentShader = graphics->createFragmentShader({shaderIndex++});
}
collection.pipelineLayout->create();
{
std::scoped_lock lock(shadersLock);
shaders[perm] = std::move(collection);
}
}