rendering: unify builtin forward and depth-style shaders
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <dxgidebug.h>
|
||||
@@ -51,7 +52,36 @@ bool CompileD3D12Shader(const ShaderCompileDesc& desc, D3D12Shader& shader) {
|
||||
const char* profilePtr = profile.empty() ? nullptr : profile.c_str();
|
||||
|
||||
if (!desc.source.empty()) {
|
||||
return shader.Compile(desc.source.data(), desc.source.size(), entryPointPtr, profilePtr);
|
||||
std::vector<std::string> macroNames;
|
||||
std::vector<std::string> macroDefinitions;
|
||||
std::vector<D3D_SHADER_MACRO> macroTable;
|
||||
if (!desc.macros.empty()) {
|
||||
macroNames.reserve(desc.macros.size());
|
||||
macroDefinitions.reserve(desc.macros.size());
|
||||
macroTable.reserve(desc.macros.size() + 1u);
|
||||
for (const ShaderCompileMacro& macro : desc.macros) {
|
||||
macroNames.push_back(NarrowAscii(macro.name));
|
||||
macroDefinitions.push_back(NarrowAscii(macro.definition));
|
||||
}
|
||||
|
||||
for (size_t macroIndex = 0; macroIndex < desc.macros.size(); ++macroIndex) {
|
||||
D3D_SHADER_MACRO d3dMacro = {};
|
||||
d3dMacro.Name = macroNames[macroIndex].c_str();
|
||||
d3dMacro.Definition = macroDefinitions[macroIndex].empty()
|
||||
? "1"
|
||||
: macroDefinitions[macroIndex].c_str();
|
||||
macroTable.push_back(d3dMacro);
|
||||
}
|
||||
macroTable.push_back({ nullptr, nullptr });
|
||||
}
|
||||
|
||||
const D3D_SHADER_MACRO* macroPtr = macroTable.empty() ? nullptr : macroTable.data();
|
||||
return shader.Compile(
|
||||
desc.source.data(),
|
||||
desc.source.size(),
|
||||
macroPtr,
|
||||
entryPointPtr,
|
||||
profilePtr);
|
||||
}
|
||||
|
||||
if (!desc.fileName.empty()) {
|
||||
|
||||
@@ -44,8 +44,26 @@ bool D3D12Shader::CompileFromFile(const wchar_t* filePath, const char* entryPoin
|
||||
}
|
||||
|
||||
bool D3D12Shader::Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) {
|
||||
HRESULT hResult = D3DCompile(sourceData, sourceSize, nullptr, nullptr, nullptr, entryPoint, target,
|
||||
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &m_bytecode, &m_error);
|
||||
return Compile(sourceData, sourceSize, nullptr, entryPoint, target);
|
||||
}
|
||||
|
||||
bool D3D12Shader::Compile(const void* sourceData,
|
||||
size_t sourceSize,
|
||||
const D3D_SHADER_MACRO* macros,
|
||||
const char* entryPoint,
|
||||
const char* target) {
|
||||
HRESULT hResult = D3DCompile(
|
||||
sourceData,
|
||||
sourceSize,
|
||||
nullptr,
|
||||
macros,
|
||||
nullptr,
|
||||
entryPoint,
|
||||
target,
|
||||
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
|
||||
0,
|
||||
&m_bytecode,
|
||||
&m_error);
|
||||
|
||||
if (FAILED(hResult)) {
|
||||
if (m_error) {
|
||||
|
||||
@@ -29,7 +29,10 @@
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
|
||||
@@ -166,6 +169,167 @@ bool LoadShaderSourceText(const ShaderCompileDesc& desc, std::string& outSourceT
|
||||
return file.read(outSourceText.data(), size).good();
|
||||
}
|
||||
|
||||
bool IsHlslShaderCompileDesc(const ShaderCompileDesc& desc) {
|
||||
if (desc.sourceLanguage == ShaderLanguage::HLSL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (desc.fileName.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string extension = std::filesystem::path(desc.fileName).extension().string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char ch) {
|
||||
return static_cast<char>(std::tolower(ch));
|
||||
});
|
||||
return extension == ".hlsl";
|
||||
}
|
||||
|
||||
void CollectHlslTextureRegisterBindings(
|
||||
const std::string& sourceText,
|
||||
std::unordered_map<std::string, GLint>& outTextureUnits,
|
||||
std::unordered_set<std::string>& outSamplerNames) {
|
||||
static const std::regex kTexturePattern(
|
||||
R"(((?:Texture2D|TextureCube)\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*register\s*\(\s*t([0-9]+)))",
|
||||
std::regex::ECMAScript);
|
||||
static const std::regex kSamplerPattern(
|
||||
R"(((?:SamplerState|SamplerComparisonState)\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*register\s*\(\s*s([0-9]+)))",
|
||||
std::regex::ECMAScript);
|
||||
|
||||
for (std::sregex_iterator it(sourceText.begin(), sourceText.end(), kTexturePattern), end; it != end; ++it) {
|
||||
const std::smatch& match = *it;
|
||||
if (match.size() < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
outTextureUnits[match[2].str()] = static_cast<GLint>(std::stoi(match[3].str()));
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
for (std::sregex_iterator it(sourceText.begin(), sourceText.end(), kSamplerPattern), end; it != end; ++it) {
|
||||
const std::smatch& match = *it;
|
||||
if (match.size() < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outSamplerNames.insert(match[2].str());
|
||||
}
|
||||
}
|
||||
|
||||
bool TryResolveCombinedSamplerTextureUnit(
|
||||
const std::string& uniformName,
|
||||
const std::unordered_map<std::string, GLint>& textureUnits,
|
||||
const std::unordered_set<std::string>& samplerNames,
|
||||
GLint& outTextureUnit) {
|
||||
static const std::string kCombinedPrefix = "SPIRV_Cross_Combined";
|
||||
if (uniformName.rfind(kCombinedPrefix, 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string combinedName = uniformName.substr(kCombinedPrefix.size());
|
||||
const size_t arraySuffixPos = combinedName.find('[');
|
||||
if (arraySuffixPos != std::string::npos) {
|
||||
combinedName = combinedName.substr(0, arraySuffixPos);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, GLint>> candidates(textureUnits.begin(), textureUnits.end());
|
||||
std::sort(
|
||||
candidates.begin(),
|
||||
candidates.end(),
|
||||
[](const auto& left, const auto& right) {
|
||||
return left.first.size() > right.first.size();
|
||||
});
|
||||
|
||||
for (const auto& [textureName, textureUnit] : candidates) {
|
||||
if (combinedName.rfind(textureName, 0) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string samplerName = combinedName.substr(textureName.size());
|
||||
if (!samplerName.empty() &&
|
||||
(samplerNames.empty() || samplerNames.find(samplerName) != samplerNames.end())) {
|
||||
outTextureUnit = textureUnit;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigureOpenGLCombinedSamplerUniforms(
|
||||
GLuint program,
|
||||
const ShaderCompileDesc* shaderDescs,
|
||||
size_t shaderDescCount) {
|
||||
if (program == 0 || shaderDescs == nullptr || shaderDescCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, GLint> textureUnits;
|
||||
std::unordered_set<std::string> samplerNames;
|
||||
for (size_t shaderIndex = 0; shaderIndex < shaderDescCount; ++shaderIndex) {
|
||||
const ShaderCompileDesc& shaderDesc = shaderDescs[shaderIndex];
|
||||
if (!IsHlslShaderCompileDesc(shaderDesc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string sourceText;
|
||||
if (!LoadShaderSourceText(shaderDesc, sourceText) || sourceText.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CollectHlslTextureRegisterBindings(sourceText, textureUnits, samplerNames);
|
||||
}
|
||||
|
||||
if (textureUnits.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLint activeUniformCount = 0;
|
||||
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &activeUniformCount);
|
||||
if (activeUniformCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLint previousProgram = 0;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgram);
|
||||
glUseProgram(program);
|
||||
|
||||
for (GLint uniformIndex = 0; uniformIndex < activeUniformCount; ++uniformIndex) {
|
||||
GLsizei nameLength = 0;
|
||||
GLint arraySize = 0;
|
||||
GLenum uniformType = 0;
|
||||
char nameBuffer[256] = {};
|
||||
glGetActiveUniform(
|
||||
program,
|
||||
static_cast<GLuint>(uniformIndex),
|
||||
static_cast<GLsizei>(std::size(nameBuffer)),
|
||||
&nameLength,
|
||||
&arraySize,
|
||||
&uniformType,
|
||||
nameBuffer);
|
||||
if (nameLength <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(void)arraySize;
|
||||
(void)uniformType;
|
||||
|
||||
GLint textureUnit = -1;
|
||||
if (!TryResolveCombinedSamplerTextureUnit(nameBuffer, textureUnits, samplerNames, textureUnit)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const GLint location = glGetUniformLocation(program, nameBuffer);
|
||||
if (location >= 0) {
|
||||
glUniform1i(location, textureUnit);
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(static_cast<GLuint>(previousProgram));
|
||||
}
|
||||
|
||||
bool TryResolveShaderTypeFromTarget(const std::wstring& profile, ShaderType& type) {
|
||||
const std::string asciiProfile = NarrowAscii(profile);
|
||||
if (asciiProfile.find("vs_") != std::string::npos || asciiProfile == "vs") {
|
||||
@@ -536,6 +700,8 @@ bool BuildOpenGLProgram(const ShaderCompileDesc* shaderDescs,
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigureOpenGLCombinedSamplerUniforms(program, shaderDescs, shaderDescCount);
|
||||
|
||||
outProgram = program;
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user