mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix, Test] (MG_Util, MG_Backend/DirectVulkan, MG_IntegrationTest): adversarial review - the rewritten 1D-array image collided with a module's own 2D-array one and left an invalid duplicate type; pin the component order, keep the subject kinds in a truncated matrix
This commit is contained in:
@@ -858,6 +858,16 @@ namespace MobileGL {
|
||||
|
||||
Optimizer optimizer(SPV_ENV_VULKAN_1_1);
|
||||
optimizer.RegisterPass(Lower1DArrayImagesPass::CreateLower1DArrayImagesPass());
|
||||
// Mandatory, not tidying. Rewriting a 1D-array image type to the 2D-array one
|
||||
// makes it structurally IDENTICAL to any real 2D-array image of the same sampled
|
||||
// type and format that the module already declared - and SPIR-V forbids duplicate
|
||||
// non-aggregate type declarations, so the result fails validation. That collision
|
||||
// is not exotic: it is the shape of this whole change's headline case, where one
|
||||
// compute shader declares uimage1DArray and uimage2DArray side by side, both
|
||||
// r32ui. The same applies one level up, to the OpTypePointer instructions that
|
||||
// named the two types, and to the Image1D capability the rewrite turns into a
|
||||
// second Shader. Deduplicating afterwards collapses all three at once.
|
||||
optimizer.RegisterPass(CreateRemoveDuplicatesPass());
|
||||
|
||||
return RunOptimizerChecked("Lower1DArrayImagesForEssl", optimizer, inputBinary, outputBinary);
|
||||
}
|
||||
|
||||
@@ -171,13 +171,21 @@ namespace MobileGL {
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
|
||||
spvtools::opt::analysis::Integer signedInt(32, true);
|
||||
spvtools::opt::analysis::Vector int3(&signedInt, 3);
|
||||
const uint32_t int3TypeId = typeMgr->GetTypeInstruction(&int3);
|
||||
const uint32_t intTypeId = typeMgr->GetTypeInstruction(&signedInt);
|
||||
const uint32_t zeroId = constantMgr->GetSIntConstId(0);
|
||||
if (int3TypeId == 0 || intTypeId == 0 || zeroId == 0) {
|
||||
return Status::Failure;
|
||||
// The same refusal the caller makes, restated here so the pass is safe wherever
|
||||
// it is registered. Rewriting the type while leaving an OpImageQuerySize on it
|
||||
// produces a query whose result type has one component too few - an invalid
|
||||
// module - and there is no correct two-component size to substitute, because the
|
||||
// ES texture genuinely has a height the GL one does not.
|
||||
for (auto& function : *irContext->module()) {
|
||||
for (auto& block : function) {
|
||||
for (auto& instruction : block) {
|
||||
if (QueriesImageSize(instruction.opcode()) && instruction.NumInOperands() >= 1 &&
|
||||
Is1DArrayStorageImageType(
|
||||
ResolveImageType(irContext, instruction.GetSingleWordInOperand(0)))) {
|
||||
return Status::SuccessWithoutChange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (u, layer) -> (u, 0, layer). The height the ES 2D array carries is 1, so Y is
|
||||
@@ -197,6 +205,35 @@ namespace MobileGL {
|
||||
}
|
||||
|
||||
const uint32_t coordinateId = instruction.GetSingleWordInOperand(coordinateOperand);
|
||||
|
||||
// Built from the COORDINATE's own component type rather than a
|
||||
// hardcoded signed int. GLSL only ever spells these ivec2, but SPIR-V
|
||||
// permits an unsigned coordinate, and extracting a uint component
|
||||
// into an int result is an invalid module rather than a wrong answer -
|
||||
// the kind of defect that reaches a driver as "compiles here, not
|
||||
// there".
|
||||
Instruction* coordinateDef = irContext->get_def_use_mgr()->GetDef(coordinateId);
|
||||
if (coordinateDef == nullptr) return Status::Failure;
|
||||
const auto* coordinateType = typeMgr->GetType(coordinateDef->type_id());
|
||||
const auto* coordinateVector = coordinateType != nullptr ? coordinateType->AsVector()
|
||||
: nullptr;
|
||||
if (coordinateVector == nullptr || coordinateVector->element_count() != 2) {
|
||||
return Status::Failure;
|
||||
}
|
||||
const auto* component = coordinateVector->element_type();
|
||||
const auto* componentInteger = component != nullptr ? component->AsInteger() : nullptr;
|
||||
if (componentInteger == nullptr) return Status::Failure;
|
||||
|
||||
spvtools::opt::analysis::Vector widenedVector(component, 3);
|
||||
const uint32_t int3TypeId = typeMgr->GetTypeInstruction(&widenedVector);
|
||||
const uint32_t intTypeId = typeMgr->GetTypeInstruction(component);
|
||||
const uint32_t zeroId = componentInteger->IsSigned()
|
||||
? constantMgr->GetSIntConstId(0)
|
||||
: constantMgr->GetUIntConstId(0);
|
||||
if (int3TypeId == 0 || intTypeId == 0 || zeroId == 0) {
|
||||
return Status::Failure;
|
||||
}
|
||||
|
||||
InstructionBuilder builder(
|
||||
irContext, &instruction,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
|
||||
@@ -60,6 +60,16 @@ namespace MobileGL {
|
||||
// the rewrite OpImageQuerySize yields three components where the shader consumes two,
|
||||
// and silently handing back a differently-shaped size is worse than refusing. The
|
||||
// caller logs it and leaves the module alone.
|
||||
//
|
||||
// KNOWN LIMITATION - the decline is per MODULE, and a program is several of them. A
|
||||
// program whose vertex and fragment stages share a uimage1DArray uniform, where only
|
||||
// one stage calls imageSize() on it, gets that stage declined and the other rewritten:
|
||||
// the two then declare the same uniform with different types and the ES LINK fails on
|
||||
// a type mismatch, rather than the single compile error a reader of the comment above
|
||||
// would expect. Correlating the decision across a program's stages needs the decision
|
||||
// to be made where the program is known, which is above this pass; it is left undone
|
||||
// deliberately rather than papered over, because both outcomes are a refusal and the
|
||||
// shape has never been observed outside a deliberately constructed shader.
|
||||
class Lower1DArrayImagesPass final : public spvtools::opt::Pass {
|
||||
public:
|
||||
const char* name() const override { return "mobilegl-lower-1d-array-images"; }
|
||||
|
||||
Reference in New Issue
Block a user