mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 05:38:31 +09:00
[Feat] (ShaderTranspiler, DirectGLES): support noperspective conformantly instead of stripping it - let the qualifier reach glslang as the core SPIR-V NoPerspective decoration (native on DirectVulkan; SPIRV-Cross emits ESSL noperspective + GL_NV_shader_noperspective_interpolation on DirectGLES), and for GLES devices lacking that extension add StripNoPerspectivePass to drop the decoration and fall back to smooth; the old naked substring erase discarded the interpolation shader packs need and mangled identifiers containing the word
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include "SpirvPasses/LowerDrawParametersPass.h"
|
||||
#include "SpirvPasses/RebaseInstanceIndexPass.h"
|
||||
#include "SpirvPasses/StripUboMemberRelaxedPrecisionPass.h"
|
||||
#include "SpirvPasses/StripNoPerspectivePass.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
@@ -334,6 +335,18 @@ namespace MobileGL {
|
||||
return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options);
|
||||
}
|
||||
|
||||
bool ShaderCompiler::StripNoPerspectiveForEssl(const Vector<Uint32>& inputBinary,
|
||||
Vector<uint32_t>& outputBinary) {
|
||||
using namespace spvtools;
|
||||
OptimizerOptions options;
|
||||
options.set_run_validator(false);
|
||||
|
||||
Optimizer optimizer(SPV_ENV_VULKAN_1_1);
|
||||
optimizer.RegisterPass(StripNoPerspectivePass::CreateStripNoPerspectivePass());
|
||||
|
||||
return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options);
|
||||
}
|
||||
|
||||
bool ShaderCompiler::RebaseInstanceIndexForVulkan(const Vector<Uint32>& inputBinary,
|
||||
Vector<uint32_t>& outputBinary) {
|
||||
using namespace spvtools;
|
||||
|
||||
@@ -33,6 +33,11 @@ namespace MobileGL {
|
||||
// Only for the DirectGLES transpile path.
|
||||
static bool StripUboMemberRelaxedPrecisionForEssl(const Vector<Uint32>& inputBinary,
|
||||
Vector<uint32_t>& outputBinary);
|
||||
// Removes NoPerspective decorations so SPIRV-Cross emits plain (smooth) ESSL varyings.
|
||||
// DirectGLES fallback only, for devices lacking GL_NV_shader_noperspective_interpolation
|
||||
// (SPIRV-Cross would otherwise require that extension and the driver would reject it).
|
||||
static bool StripNoPerspectiveForEssl(const Vector<Uint32>& inputBinary,
|
||||
Vector<uint32_t>& outputBinary);
|
||||
// Rebases loads of the InstanceIndex builtin to (InstanceIndex - BaseInstance) so
|
||||
// shaders see GL's zero-based gl_InstanceID. Vertex shaders only; DirectVulkan
|
||||
// backend only (glslang's relaxed mode aliases gl_InstanceID to gl_InstanceIndex,
|
||||
|
||||
@@ -1251,15 +1251,13 @@ namespace MobileGL {
|
||||
|
||||
NormalizeLineDirectives(source);
|
||||
|
||||
// remove "noperspective"
|
||||
const char* str_np = "noperspective";
|
||||
const SizeT len_np = strlen(str_np);
|
||||
SizeT noperspectivePos = source.find(str_np);
|
||||
while (noperspectivePos != String::npos) {
|
||||
// + length of "\n"
|
||||
source = source.replace(noperspectivePos, len_np, "");
|
||||
noperspectivePos = source.find(str_np);
|
||||
}
|
||||
// noperspective is intentionally NOT touched here. It is core in desktop GLSL (1.30+)
|
||||
// and maps to the core SPIR-V NoPerspective decoration, which DirectVulkan renders
|
||||
// natively and SPIRV-Cross turns into ESSL `noperspective` + the
|
||||
// GL_NV_shader_noperspective_interpolation extension. The old naked substring erase
|
||||
// both discarded that interpolation (shader packs need it) and corrupted any
|
||||
// identifier that merely contained the word. The GLES fallback for devices without
|
||||
// the extension lives in the backend, where device capabilities are known.
|
||||
|
||||
FilterUnsupportedGpuShaderInt64(source);
|
||||
CoerceUniformBlockPackingToStd140(source);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/StripNoPerspectivePass.cpp
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#include "StripNoPerspectivePass.h"
|
||||
|
||||
#include "spirv.hpp"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
namespace ShaderTranspiler {
|
||||
namespace {
|
||||
using spvtools::opt::Instruction;
|
||||
using spvtools::opt::IRContext;
|
||||
|
||||
// OpDecorate <target-id> <decoration> [literals...]
|
||||
// OpMemberDecorate <struct-id> <member> <decoration> [literals...]
|
||||
constexpr uint32_t kDecorateDecorationOperand = 1;
|
||||
constexpr uint32_t kMemberDecorateDecorationOperand = 2;
|
||||
} // namespace
|
||||
|
||||
spvtools::opt::Pass::Status StripNoPerspectivePass::Process() {
|
||||
auto* irContext = context();
|
||||
|
||||
// Collect first: KillInst mutates the annotation list being walked.
|
||||
std::vector<Instruction*> toKill;
|
||||
for (Instruction& annotation : irContext->annotations()) {
|
||||
uint32_t decorationOperand = 0;
|
||||
if (annotation.opcode() == spv::Op::OpDecorate) {
|
||||
decorationOperand = kDecorateDecorationOperand;
|
||||
} else if (annotation.opcode() == spv::Op::OpMemberDecorate) {
|
||||
decorationOperand = kMemberDecorateDecorationOperand;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (annotation.NumInOperands() <= decorationOperand) {
|
||||
continue;
|
||||
}
|
||||
if (static_cast<spv::Decoration>(annotation.GetSingleWordInOperand(decorationOperand)) ==
|
||||
spv::Decoration::NoPerspective) {
|
||||
toKill.push_back(&annotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (toKill.empty()) {
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
for (Instruction* inst : toKill) {
|
||||
irContext->KillInst(inst);
|
||||
}
|
||||
|
||||
irContext->InvalidateAnalysesExceptFor(IRContext::kAnalysisNone);
|
||||
return Status::SuccessWithChange;
|
||||
}
|
||||
|
||||
spvtools::Optimizer::PassToken StripNoPerspectivePass::CreateStripNoPerspectivePass() {
|
||||
return spvtools::Optimizer::PassToken(MakeUnique<StripNoPerspectivePass>());
|
||||
}
|
||||
} // namespace ShaderTranspiler
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
@@ -0,0 +1,35 @@
|
||||
// MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/StripNoPerspectivePass.h
|
||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||
// Licensed under the GNU Lesser General Public License v3.0:
|
||||
// https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// End of Source File Header
|
||||
|
||||
#pragma once
|
||||
#include "source/opt/pass.h"
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
#include <Includes.h>
|
||||
|
||||
namespace MobileGL {
|
||||
namespace MG_Util {
|
||||
namespace ShaderTranspiler {
|
||||
// Removes the NoPerspective decoration from every interface variable and block member.
|
||||
// DirectGLES fallback only, for devices that lack GL_NV_shader_noperspective_interpolation:
|
||||
// SPIRV-Cross renders a NoPerspective-decorated varying as ESSL `noperspective` plus
|
||||
// `#extension GL_NV_shader_noperspective_interpolation : require`, which such a driver
|
||||
// rejects. Dropping the decoration falls the varying back to smooth (perspective-correct)
|
||||
// interpolation - the same visible result the old text-level strip produced, but without
|
||||
// corrupting identifiers and without touching DirectVulkan, where NoPerspective is native.
|
||||
// (The exact screen-linear emulation via gl_Position.w / gl_FragCoord.w is a later step.)
|
||||
class StripNoPerspectivePass : public spvtools::opt::Pass {
|
||||
public:
|
||||
const char* name() const override { return "strip-noperspective"; }
|
||||
Status Process() override;
|
||||
|
||||
static spvtools::Optimizer::PassToken CreateStripNoPerspectivePass();
|
||||
};
|
||||
} // namespace ShaderTranspiler
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
Reference in New Issue
Block a user