rendering: unify builtin forward and depth-style shaders

This commit is contained in:
2026-04-07 03:35:06 +08:00
parent 503ffbc4ff
commit 5f9f3386ab
27 changed files with 1135 additions and 1151 deletions

View File

@@ -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()) {

View File

@@ -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) {

View File

@@ -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;
}