rendering: remove builtin authoring register annotations

This commit is contained in:
2026-04-07 10:34:20 +08:00
parent ec06340f58
commit f31fece2ce
11 changed files with 565 additions and 80 deletions

View File

@@ -5,13 +5,13 @@ Shader "Builtin Color Scale Post Process"
_ColorScale ("Color Scale", Color) = (0.65,0.80,1.00,1.0)
}
HLSLINCLUDE
cbuffer PostProcessConstants : register(b0)
cbuffer PostProcessConstants
{
float4 gColorScale;
};
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
Texture2D gSourceColorTexture;
SamplerState gLinearClampSampler;
struct VSOutput
{

View File

@@ -7,21 +7,21 @@ Shader "Builtin Depth Only"
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
}
HLSLINCLUDE
cbuffer PerObjectConstants : register(b0)
cbuffer PerObjectConstants
{
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
float4x4 gModelMatrix;
};
cbuffer MaterialConstants : register(b1)
cbuffer MaterialConstants
{
float4 gBaseColorFactor;
float4 gAlphaCutoffParams;
};
Texture2D BaseColorTexture : register(t0);
SamplerState LinearClampSampler : register(s0);
Texture2D BaseColorTexture;
SamplerState LinearClampSampler;
struct VSInput
{

View File

@@ -8,14 +8,14 @@ Shader "Builtin Final Color"
_ToneMappingMode ("Tone Mapping Mode", Float) = 0.0
}
HLSLINCLUDE
cbuffer FinalColorConstants : register(b0)
cbuffer FinalColorConstants
{
float4 gColorScale;
float4 gFinalColorParams;
};
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
Texture2D gSourceColorTexture;
SamplerState gLinearClampSampler;
struct VSOutput
{

View File

@@ -7,7 +7,7 @@ Shader "Builtin Forward Lit"
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
}
HLSLINCLUDE
cbuffer PerObjectConstants : register(b0)
cbuffer PerObjectConstants
{
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
@@ -25,7 +25,7 @@ Shader "Builtin Forward Lit"
float4 spotAnglesAndFlags;
};
cbuffer LightingConstants : register(b1)
cbuffer LightingConstants
{
float4 gMainLightDirectionAndIntensity;
float4 gMainLightColorAndFlags;
@@ -33,23 +33,23 @@ Shader "Builtin Forward Lit"
AdditionalLightData gAdditionalLights[XC_MAX_ADDITIONAL_LIGHTS];
};
cbuffer MaterialConstants : register(b2)
cbuffer MaterialConstants
{
float4 gBaseColorFactor;
float4 gAlphaCutoffParams;
};
cbuffer ShadowReceiverConstants : register(b3)
cbuffer ShadowReceiverConstants
{
float4x4 gWorldToShadowMatrix;
float4 gShadowBiasAndTexelSize;
float4 gShadowOptions;
};
Texture2D BaseColorTexture : register(t0);
SamplerState LinearClampSampler : register(s0);
Texture2D ShadowMapTexture : register(t1);
SamplerState ShadowMapSampler : register(s1);
Texture2D BaseColorTexture;
SamplerState LinearClampSampler;
Texture2D ShadowMapTexture;
SamplerState ShadowMapSampler;
struct VSInput
{

View File

@@ -13,7 +13,7 @@ Shader "Builtin Object Id"
#pragma target 4.5
#pragma vertex MainVS
#pragma fragment MainPS
cbuffer PerObjectConstants : register(b0)
cbuffer PerObjectConstants
{
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;

View File

@@ -7,21 +7,21 @@ Shader "Builtin Shadow Caster"
_MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)]
}
HLSLINCLUDE
cbuffer PerObjectConstants : register(b0)
cbuffer PerObjectConstants
{
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
float4x4 gModelMatrix;
};
cbuffer MaterialConstants : register(b1)
cbuffer MaterialConstants
{
float4 gBaseColorFactor;
float4 gAlphaCutoffParams;
};
Texture2D BaseColorTexture : register(t0);
SamplerState LinearClampSampler : register(s0);
Texture2D BaseColorTexture;
SamplerState LinearClampSampler;
struct VSInput
{

View File

@@ -9,7 +9,7 @@ Shader "Builtin Skybox"
_Tex ("Cubemap (HDR)", Cube) = "white" [Semantic(SkyboxTexture)]
}
HLSLINCLUDE
cbuffer EnvironmentConstants : register(b0)
cbuffer EnvironmentConstants
{
float4 gSkyboxTopColor;
float4 gSkyboxHorizonColor;
@@ -19,15 +19,15 @@ Shader "Builtin Skybox"
float4 gCameraForwardAndUnused;
};
cbuffer MaterialConstants : register(b1)
cbuffer MaterialConstants
{
float4 gSkyboxTintAndExposure;
float4 gSkyboxRotationAndMode;
};
Texture2D SkyboxPanoramicTexture : register(t0);
TextureCube SkyboxTexture : register(t1);
SamplerState LinearClampSampler : register(s0);
Texture2D SkyboxPanoramicTexture;
TextureCube SkyboxTexture;
SamplerState LinearClampSampler;
struct VSOutput
{

View File

@@ -18,7 +18,7 @@ Shader "Builtin Unlit"
#pragma target 4.5
#pragma vertex MainVS
#pragma fragment MainPS
cbuffer PerObjectConstants : register(b0)
cbuffer PerObjectConstants
{
float4x4 gProjectionMatrix;
float4x4 gViewMatrix;
@@ -26,13 +26,13 @@ Shader "Builtin Unlit"
float4x4 gNormalMatrix;
};
cbuffer MaterialConstants : register(b1)
cbuffer MaterialConstants
{
float4 gBaseColorFactor;
};
Texture2D BaseColorTexture : register(t0);
SamplerState LinearClampSampler : register(s0);
Texture2D BaseColorTexture;
SamplerState LinearClampSampler;
struct VSInput
{

View File

@@ -190,10 +190,10 @@ void CollectHlslTextureRegisterBindings(
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]+)))",
R"(((?:Texture2D|TextureCube)\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*register\s*\(\s*t([0-9]+)(?:\s*,\s*space[0-9]+)?\s*\)))",
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]+)))",
R"(((?:SamplerState|SamplerComparisonState)\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*register\s*\(\s*s([0-9]+)(?:\s*,\s*space[0-9]+)?\s*\)))",
std::regex::ECMAScript);
for (std::sregex_iterator it(sourceText.begin(), sourceText.end(), kTexturePattern), end; it != end; ++it) {

View File

@@ -3,8 +3,10 @@
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/RHI/RHIEnums.h>
#include <XCEngine/RHI/RHIPipelineState.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h>
#include <XCEngine/Resources/Shader/Shader.h>
#include <regex>
#include <string>
namespace XCEngine {
@@ -44,6 +46,316 @@ inline std::wstring ToWideAscii(const Containers::String& value) {
return wide;
}
inline std::string ToStdString(const Containers::String& value) {
return std::string(value.CStr(), value.Length());
}
inline std::string EscapeRegexLiteral(const Containers::String& value) {
std::string escaped;
escaped.reserve(value.Length() * 2u);
for (size_t index = 0; index < value.Length(); ++index) {
const char ch = value[index];
switch (ch) {
case '\\':
case '^':
case '$':
case '.':
case '|':
case '?':
case '*':
case '+':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
escaped.push_back('\\');
break;
default:
break;
}
escaped.push_back(ch);
}
return escaped;
}
inline bool TryCollectShaderPassResourceBindings(
const Resources::ShaderPass& pass,
Containers::Array<Resources::ShaderResourceBindingDesc>& outBindings) {
outBindings.Clear();
if (!pass.resources.Empty()) {
outBindings.Reserve(pass.resources.Size());
for (const Resources::ShaderResourceBindingDesc& binding : pass.resources) {
outBindings.PushBack(binding);
}
return true;
}
return TryBuildImplicitBuiltinPassResourceBindings(pass, outBindings);
}
inline Containers::String ResolveLegacyHlslBindingDeclarationAlias(
const Resources::ShaderResourceBindingDesc& binding) {
switch (ResolveBuiltinPassResourceSemantic(binding)) {
case BuiltinPassResourceSemantic::BaseColorTexture:
return "gBaseColorTexture";
case BuiltinPassResourceSemantic::ShadowMapTexture:
return "gShadowMapTexture";
case BuiltinPassResourceSemantic::LinearClampSampler:
return "gLinearSampler";
case BuiltinPassResourceSemantic::ShadowMapSampler:
return "gShadowMapSampler";
case BuiltinPassResourceSemantic::Unknown:
default:
return Containers::String();
}
}
inline bool TryRewriteHlslRegisterBindingWithName(
std::string& sourceText,
const Containers::String& declarationName,
const char* registerPrefix,
Core::uint32 bindingIndex,
Core::uint32 setIndex,
bool includeRegisterSpace,
Resources::ShaderResourceType resourceType) {
if (declarationName.Empty()) {
return false;
}
const std::string registerClause =
includeRegisterSpace
? std::string("register(") + registerPrefix +
std::to_string(bindingIndex) +
", space" +
std::to_string(setIndex) +
")"
: std::string("register(") + registerPrefix +
std::to_string(bindingIndex) +
")";
const std::string escapedName = EscapeRegexLiteral(declarationName);
if (resourceType == Resources::ShaderResourceType::ConstantBuffer) {
const std::regex pattern(
"(cbuffer\\s+" + escapedName + "\\s*)(:\\s*register\\s*\\([^\\)]*\\))?(\\s*\\{)",
std::regex::ECMAScript);
const std::string rewritten =
std::regex_replace(sourceText, pattern, "$1: " + registerClause + "$3");
if (rewritten != sourceText) {
sourceText = rewritten;
return true;
}
return false;
}
const std::regex pattern(
"((?:Texture2D|TextureCube|SamplerState|SamplerComparisonState)\\s+" + escapedName +
"\\s*)(:\\s*register\\s*\\([^\\)]*\\))?(\\s*;)",
std::regex::ECMAScript);
const std::string rewritten =
std::regex_replace(sourceText, pattern, "$1: " + registerClause + "$3");
if (rewritten != sourceText) {
sourceText = rewritten;
return true;
}
return false;
}
inline const char* TryGetHlslRegisterPrefix(Resources::ShaderResourceType type) {
switch (type) {
case Resources::ShaderResourceType::ConstantBuffer:
return "b";
case Resources::ShaderResourceType::Texture2D:
case Resources::ShaderResourceType::TextureCube:
return "t";
case Resources::ShaderResourceType::Sampler:
return "s";
default:
return nullptr;
}
}
inline bool TryRewriteHlslRegisterBinding(
std::string& sourceText,
const Resources::ShaderResourceBindingDesc& binding,
bool includeRegisterSpace) {
const char* registerPrefix = TryGetHlslRegisterPrefix(binding.type);
if (registerPrefix == nullptr) {
return false;
}
if (TryRewriteHlslRegisterBindingWithName(
sourceText,
binding.name,
registerPrefix,
binding.binding,
binding.set,
includeRegisterSpace,
binding.type)) {
return true;
}
const Containers::String legacyAlias = ResolveLegacyHlslBindingDeclarationAlias(binding);
if (legacyAlias != binding.name &&
TryRewriteHlslRegisterBindingWithName(
sourceText,
legacyAlias,
registerPrefix,
binding.binding,
binding.set,
includeRegisterSpace,
binding.type)) {
return true;
}
if ((binding.type == Resources::ShaderResourceType::Texture2D ||
binding.type == Resources::ShaderResourceType::TextureCube ||
binding.type == Resources::ShaderResourceType::Sampler)) {
const Containers::String prefixedName = Containers::String("g") + binding.name;
if (prefixedName != binding.name &&
prefixedName != legacyAlias &&
TryRewriteHlslRegisterBindingWithName(
sourceText,
prefixedName,
registerPrefix,
binding.binding,
binding.set,
includeRegisterSpace,
binding.type)) {
return true;
}
}
return false;
}
inline bool TryBuildRuntimeShaderBindings(
const Resources::ShaderPass& pass,
Resources::ShaderBackend backend,
Containers::Array<Resources::ShaderResourceBindingDesc>& outBindings,
bool& outIncludeRegisterSpace) {
outBindings.Clear();
outIncludeRegisterSpace = false;
if (backend == Resources::ShaderBackend::Vulkan) {
outIncludeRegisterSpace = true;
return TryCollectShaderPassResourceBindings(pass, outBindings);
}
if (backend != Resources::ShaderBackend::D3D12 &&
backend != Resources::ShaderBackend::OpenGL) {
return false;
}
if (!pass.resources.Empty()) {
return false;
}
if (!TryBuildImplicitBuiltinPassResourceBindings(pass, outBindings)) {
return false;
}
Core::uint32 nextConstantBufferRegister = 0;
Core::uint32 nextTextureRegister = 0;
Core::uint32 nextSamplerRegister = 0;
Core::uint32 nextUnorderedAccessRegister = 0;
for (Resources::ShaderResourceBindingDesc& binding : outBindings) {
binding.set = 0;
switch (binding.type) {
case Resources::ShaderResourceType::ConstantBuffer:
binding.binding = nextConstantBufferRegister++;
break;
case Resources::ShaderResourceType::Texture2D:
case Resources::ShaderResourceType::TextureCube:
binding.binding = nextTextureRegister++;
break;
case Resources::ShaderResourceType::Sampler:
binding.binding = nextSamplerRegister++;
break;
default:
binding.binding = nextUnorderedAccessRegister++;
break;
}
}
return true;
}
inline std::string BuildRuntimeShaderSource(
const Resources::ShaderPass& pass,
Resources::ShaderBackend backend,
const Resources::ShaderStageVariant& variant) {
std::string sourceText = ToStdString(variant.sourceCode);
if (variant.language != Resources::ShaderLanguage::HLSL ||
backend == Resources::ShaderBackend::Generic) {
return sourceText;
}
Containers::Array<Resources::ShaderResourceBindingDesc> bindings;
bool includeRegisterSpace = false;
if (!TryBuildRuntimeShaderBindings(pass, backend, bindings, includeRegisterSpace)) {
return sourceText;
}
for (const Resources::ShaderResourceBindingDesc& binding : bindings) {
TryRewriteHlslRegisterBinding(sourceText, binding, includeRegisterSpace);
}
return sourceText;
}
inline void AddShaderCompileMacro(
RHI::ShaderCompileDesc& compileDesc,
const wchar_t* name,
const wchar_t* definition = L"1") {
if (name == nullptr || *name == L'\0') {
return;
}
for (const RHI::ShaderCompileMacro& existingMacro : compileDesc.macros) {
if (existingMacro.name == name) {
return;
}
}
RHI::ShaderCompileMacro macro = {};
macro.name = name;
macro.definition = definition != nullptr ? definition : L"";
compileDesc.macros.push_back(std::move(macro));
}
inline void InjectUnityStyleBackendMacros(
Resources::ShaderBackend backend,
RHI::ShaderCompileDesc& compileDesc) {
switch (backend) {
case Resources::ShaderBackend::OpenGL:
AddShaderCompileMacro(compileDesc, L"SHADER_API_GLCORE");
AddShaderCompileMacro(compileDesc, L"UNITY_UV_STARTS_AT_TOP", L"0");
AddShaderCompileMacro(compileDesc, L"UNITY_NEAR_CLIP_VALUE", L"-1");
break;
case Resources::ShaderBackend::Vulkan:
AddShaderCompileMacro(compileDesc, L"SHADER_API_VULKAN");
AddShaderCompileMacro(compileDesc, L"UNITY_UV_STARTS_AT_TOP", L"1");
AddShaderCompileMacro(compileDesc, L"UNITY_NEAR_CLIP_VALUE", L"0");
break;
case Resources::ShaderBackend::D3D12:
AddShaderCompileMacro(compileDesc, L"SHADER_API_D3D12");
AddShaderCompileMacro(compileDesc, L"UNITY_UV_STARTS_AT_TOP", L"1");
AddShaderCompileMacro(compileDesc, L"UNITY_NEAR_CLIP_VALUE", L"0");
break;
case Resources::ShaderBackend::Generic:
default:
break;
}
}
inline void ApplyShaderStageVariant(
const Resources::ShaderStageVariant& variant,
RHI::ShaderCompileDesc& compileDesc) {
@@ -55,6 +367,19 @@ inline void ApplyShaderStageVariant(
compileDesc.profile = ToWideAscii(variant.profile);
}
inline void ApplyShaderStageVariant(
const Resources::ShaderPass& pass,
Resources::ShaderBackend backend,
const Resources::ShaderStageVariant& variant,
RHI::ShaderCompileDesc& compileDesc) {
const std::string sourceText = BuildRuntimeShaderSource(pass, backend, variant);
compileDesc.source.assign(sourceText.begin(), sourceText.end());
compileDesc.sourceLanguage = ToRHIShaderLanguage(variant.language);
compileDesc.entryPoint = ToWideAscii(variant.entryPoint);
compileDesc.profile = ToWideAscii(variant.profile);
InjectUnityStyleBackendMacros(backend, compileDesc);
}
inline Containers::String BuildShaderKeywordSignature(
const Resources::ShaderKeywordSet& keywordSet) {
Resources::ShaderKeywordSet normalizedKeywords = keywordSet;