mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Fix, Test] (MG_Util, MG_Backend/DirectVulkan, MG_IntegrationTest): review round - one module parse for the shaders with no 1D-array image, per-kind values the combined case can name, and the invariants two shared buffers rest on
This commit is contained in:
@@ -839,7 +839,16 @@ namespace MobileGL {
|
||||
// MGLOG_I, deliberately: MGLOG_E/W are compiled out at the INFO level every CI,
|
||||
// retrace and release build uses, and this is exactly the diagnostic that has to
|
||||
// survive to explain the shader the driver is about to reject.
|
||||
if (Lower1DArrayImagesPass::BinaryQueriesA1DArrayStorageImageSize(inputBinary)) {
|
||||
const auto traits = Lower1DArrayImagesPass::InspectBinary(inputBinary);
|
||||
// The overwhelmingly common answer, and the reason the inspection exists: no
|
||||
// 1D-array storage image, so the module is handed back byte for byte without an
|
||||
// Optimizer ever being built. Every ESSL shader in the process passes through
|
||||
// here, so the cost of the case with nothing to do is the cost of this pass.
|
||||
if (!traits.declaresImage) {
|
||||
outputBinary = inputBinary;
|
||||
return true;
|
||||
}
|
||||
if (traits.queriesImageSize) {
|
||||
MGLOG_I("[spirv] Lower1DArrayImagesForEssl: the module queries the size of a 1D-array "
|
||||
"storage image, which cannot be answered in the 2D-array shape ES stores it in; "
|
||||
"leaving the module alone, and a strict ES driver will reject it");
|
||||
|
||||
@@ -112,16 +112,30 @@ namespace MobileGL {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool Lower1DArrayImagesPass::BinaryQueriesA1DArrayStorageImageSize(const Vector<Uint32>& binary) {
|
||||
Lower1DArrayImagesPass::ModuleTraits Lower1DArrayImagesPass::InspectBinary(const Vector<Uint32>& binary) {
|
||||
ModuleTraits traits{};
|
||||
if (binary.empty()) {
|
||||
return false;
|
||||
return traits;
|
||||
}
|
||||
std::unique_ptr<IRContext> context = spvtools::BuildModule(
|
||||
SPV_ENV_VULKAN_1_1, [](spv_message_level_t, const char*, const spv_position_t&, const char*) {},
|
||||
binary.data(), binary.size());
|
||||
if (!context) {
|
||||
return false;
|
||||
return traits;
|
||||
}
|
||||
|
||||
// The type table settles it for the cheap half, and it is the half almost every
|
||||
// shader takes: no such type declared, nothing to inspect further.
|
||||
for (const Instruction& type : context->module()->types_values()) {
|
||||
if (Is1DArrayStorageImageType(&type)) {
|
||||
traits.declaresImage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!traits.declaresImage) {
|
||||
return traits;
|
||||
}
|
||||
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto& block : function) {
|
||||
for (auto& instruction : block) {
|
||||
@@ -130,12 +144,13 @@ namespace MobileGL {
|
||||
}
|
||||
if (Is1DArrayStorageImageType(
|
||||
ResolveImageType(context.get(), instruction.GetSingleWordInOperand(0)))) {
|
||||
return true;
|
||||
traits.queriesImageSize = true;
|
||||
return traits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return traits;
|
||||
}
|
||||
|
||||
spvtools::opt::Pass::Status Lower1DArrayImagesPass::Process() {
|
||||
|
||||
@@ -65,11 +65,22 @@ namespace MobileGL {
|
||||
const char* name() const override { return "mobilegl-lower-1d-array-images"; }
|
||||
Status Process() override;
|
||||
|
||||
// True when the module declares a 1D-array storage image whose size is queried,
|
||||
// which is the shape this pass refuses to translate. Checked by the caller before
|
||||
// running, so a declined module is handed on untouched rather than partly
|
||||
// rewritten.
|
||||
static bool BinaryQueriesA1DArrayStorageImageSize(const Vector<Uint32>& binary);
|
||||
// What one inspection of a binary tells the caller. Both answers come from a
|
||||
// SINGLE parse on purpose: every ESSL shader in the process reaches this, and
|
||||
// almost none of them declare a 1D-array storage image, so the common path has to
|
||||
// cost one module parse and no optimizer run at all - not one parse to ask about
|
||||
// size queries and a second inside an Optimizer that then early-outs.
|
||||
struct ModuleTraits {
|
||||
// The module declares a 1D-array storage image, i.e. there is anything to do.
|
||||
bool declaresImage = false;
|
||||
// ...and queries its size, which is the shape this pass refuses to translate:
|
||||
// afterwards the image is a 2D array, so the query yields three components
|
||||
// where the shader consumes two, and there is no correct two-component answer
|
||||
// to substitute. The caller leaves such a module alone rather than half
|
||||
// rewriting it.
|
||||
bool queriesImageSize = false;
|
||||
};
|
||||
static ModuleTraits InspectBinary(const Vector<Uint32>& binary);
|
||||
|
||||
static spvtools::Optimizer::PassToken CreateLower1DArrayImagesPass();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user