mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-13 06: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:
@@ -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