mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 13:48:30 +09:00
[Fix] (DirectGLES, ShaderTranspiler): widen the formats SPIRV-Cross refuses to print even where GL_NV_image_formats exists
This commit is contained in:
@@ -5181,12 +5181,23 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whether the ESSL chain will re-declare an image of this format in a core carrier
|
// Whether the ESSL chain will re-declare an image of this format in a core carrier
|
||||||
// and mask its accesses (WidenImageFormatsForEssl). Armed only where there is no
|
// and mask its accesses (WidenImageFormatsForEssl). The same rule
|
||||||
// GL_NV_image_formats to spell the format natively - a driver that has the extension
|
// TextureImpl::GetImageBindableStorageWidening applies to the storage and the bind -
|
||||||
// keeps the declaration and gets the `#extension` directive instead.
|
// the three layers move together or the shader addresses a texel size the storage
|
||||||
|
// does not have.
|
||||||
|
//
|
||||||
|
// Without GL_NV_image_formats there is no legal spelling for any non-core format, so
|
||||||
|
// everything carriable widens. WITH the extension only the formats SPIRV-Cross
|
||||||
|
// refuses to print do: it throws for its is_desktop_only_format set instead of
|
||||||
|
// emitting a token, and the throw loses the stage however willing the driver was.
|
||||||
Bool ImageFormatWillBeWidened(Uint glInternalFormat) {
|
Bool ImageFormatWillBeWidened(Uint glInternalFormat) {
|
||||||
return !g_GLESCapabilities.SupportsExtendedImageFormats && glInternalFormat != 0 &&
|
if (glInternalFormat == 0) return false;
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::WidenedCoreEsslImageFormat(glInternalFormat) != 0;
|
if (MG_Util::ShaderTranspiler::ShaderCompiler::WidenedCoreEsslImageFormat(glInternalFormat) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !g_GLESCapabilities.SupportsExtendedImageFormats ||
|
||||||
|
!MG_Util::ShaderTranspiler::ShaderCompiler::SpirvCrossCanPrintEsslImageFormat(
|
||||||
|
glInternalFormat);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -5229,7 +5240,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// channels GL says they have (WidenImageFormatsForEssl, and the matching
|
// channels GL says they have (WidenImageFormatsForEssl, and the matching
|
||||||
// storage/bind widening in TextureImpl). Those need neither the extension
|
// storage/bind widening in TextureImpl). Those need neither the extension
|
||||||
// nor the diagnostic: there IS a legal spelling for them now.
|
// nor the diagnostic: there IS a legal spelling for them now.
|
||||||
if (!ImageFormatWillBeWidened(GLInternalFormatOfLayoutFormat(declaredFormat))) {
|
if (ImageFormatWillBeWidened(GLInternalFormatOfLayoutFormat(declaredFormat))) {
|
||||||
|
inputs.declaresWidenableImageFormat = true;
|
||||||
|
} else {
|
||||||
inputs.needsExtendedImageFormats = true;
|
inputs.needsExtendedImageFormats = true;
|
||||||
if (!g_GLESCapabilities.SupportsExtendedImageFormats) {
|
if (!g_GLESCapabilities.SupportsExtendedImageFormats) {
|
||||||
// From the OWNED TypeFacts, not from a live TType: the reflection
|
// From the OWNED TypeFacts, not from a live TType: the reflection
|
||||||
@@ -5277,6 +5290,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
name, MG_Util::ShaderTranspiler::ShaderCompiler::EsslImageFormatSpelling(boundFormat));
|
name, MG_Util::ShaderTranspiler::ShaderCompiler::EsslImageFormatSpelling(boundFormat));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// The bake writes this format INTO the module, so the widening that runs
|
||||||
|
// straight after has to be armed for it even though nothing DECLARED it.
|
||||||
|
inputs.declaresWidenableImageFormat = true;
|
||||||
} else {
|
} else {
|
||||||
inputs.needsExtendedImageFormats = true;
|
inputs.needsExtendedImageFormats = true;
|
||||||
}
|
}
|
||||||
@@ -5413,11 +5429,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Declares* probes each cost a BuildModule per stage, and on a driver where both
|
// Declares* probes each cost a BuildModule per stage, and on a driver where both
|
||||||
// gates are armed (Mali: no GL_OES_viewport_array AND integer multisample
|
// gates are armed (Mali: no GL_OES_viewport_array AND integer multisample
|
||||||
// squeezed to 1) the doubled parse made compile-heavy workloads ~10% slower.
|
// squeezed to 1) the doubled parse made compile-heavy workloads ~10% slower.
|
||||||
// Probing the pre-lowering module is sound for all three gates: demoting
|
// Probing the pre-lowering module is sound for both gates: demoting
|
||||||
// gl_ViewportIndex neither adds nor removes multisampled image types, and no pass
|
// gl_ViewportIndex neither adds nor removes multisampled image types.
|
||||||
// between here and the widening changes which image FORMATS the module declares -
|
|
||||||
// Lower1DArrayImagesPass rebuilds an image type but copies its format operand across,
|
|
||||||
// and the one pass that can introduce a format (the bake) reports for itself below.
|
|
||||||
// Recomputed here rather than calling GL_Getter's GetAdvertisedMaxSamples():
|
// Recomputed here rather than calling GL_Getter's GetAdvertisedMaxSamples():
|
||||||
// this is backend code and must not reach into the GL frontend. 4 is that
|
// this is backend code and must not reach into the GL frontend. 4 is that
|
||||||
// translation unit's kFrontendMaxSamples, which is the source of truth -
|
// translation unit's kFrontendMaxSamples, which is the source of truth -
|
||||||
@@ -5429,13 +5442,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESCapabilities.MaxColorTextureSamples < advertisedMaxSamples ||
|
g_GLESCapabilities.MaxColorTextureSamples < advertisedMaxSamples ||
|
||||||
g_GLESCapabilities.MaxIntegerSamples < advertisedMaxSamples ||
|
g_GLESCapabilities.MaxIntegerSamples < advertisedMaxSamples ||
|
||||||
g_GLESCapabilities.MaxDepthTextureSamples < advertisedMaxSamples;
|
g_GLESCapabilities.MaxDepthTextureSamples < advertisedMaxSamples;
|
||||||
// The image-format widening is armed on EVERY real device (no driver tested advertises
|
// The image-format widening is armed on EVERY driver, so its probe has to ride the
|
||||||
// GL_NV_image_formats), so its probe has to ride the shared parse rather than add one:
|
// shared parse rather than add one: it is asked of every stage of every program, and
|
||||||
// it is asked of every stage of every program, and a BuildModule per stage per gate is
|
// a BuildModule per stage per gate is exactly what cost compile-heavy CTS cases ~10%
|
||||||
// exactly what cost compile-heavy CTS cases ~10% before this struct existed.
|
// before this struct existed. What differs per driver is only HOW MUCH it widens -
|
||||||
const Bool imageFormatWideningArmed = !g_GLESCapabilities.SupportsExtendedImageFormats;
|
// everything carriable where there is no GL_NV_image_formats to spell the narrow
|
||||||
|
// format, and only the formats SPIRV-Cross refuses to print where there is.
|
||||||
|
const Bool widenOnlyUnprintableImageFormats = g_GLESCapabilities.SupportsExtendedImageFormats;
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::SpirvGateFeatures spirvGates;
|
MG_Util::ShaderTranspiler::ShaderCompiler::SpirvGateFeatures spirvGates;
|
||||||
if (viewportLoweringArmed || sampleClampArmed || imageFormatWideningArmed) {
|
if (viewportLoweringArmed || sampleClampArmed) {
|
||||||
spirvGates = MG_Util::ShaderTranspiler::ShaderCompiler::ProbeSpirvGateFeatures(
|
spirvGates = MG_Util::ShaderTranspiler::ShaderCompiler::ProbeSpirvGateFeatures(
|
||||||
*effectiveSpirv);
|
*effectiveSpirv);
|
||||||
}
|
}
|
||||||
@@ -5615,7 +5630,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// whose images all declare formats, and the cheap probe keeps a program that has
|
// whose images all declare formats, and the cheap probe keeps a program that has
|
||||||
// an unbound format-less image from paying an optimizer round trip per stage.
|
// an unbound format-less image from paying an optimizer round trip per stage.
|
||||||
Vector<unsigned int> imageFormatSpirv;
|
Vector<unsigned int> imageFormatSpirv;
|
||||||
Bool bakedAWidenableImageFormat = false;
|
|
||||||
if (!imageFormatBake.glFormatByUniformName.empty() &&
|
if (!imageFormatBake.glFormatByUniformName.empty() &&
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::DeclaresFormatlessStorageImage(*effectiveSpirv) &&
|
MG_Util::ShaderTranspiler::ShaderCompiler::DeclaresFormatlessStorageImage(*effectiveSpirv) &&
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::BakeImageFormatsForEssl(
|
MG_Util::ShaderTranspiler::ShaderCompiler::BakeImageFormatsForEssl(
|
||||||
@@ -5623,19 +5637,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
enableSpirvValidation) &&
|
enableSpirvValidation) &&
|
||||||
!imageFormatSpirv.empty()) {
|
!imageFormatSpirv.empty()) {
|
||||||
effectiveSpirv = &imageFormatSpirv;
|
effectiveSpirv = &imageFormatSpirv;
|
||||||
// The bake can put a format into the module that was not there when the gate
|
|
||||||
// probe above parsed it, so the probe's verdict is stale for exactly this case.
|
|
||||||
// Answered from the bake's own map rather than by re-parsing: an entry the map
|
|
||||||
// does not carry cannot have been baked. Conservative in the harmless direction -
|
|
||||||
// the pass declines individual uniforms the map names, and a widening run that
|
|
||||||
// finds nothing to widen only costs a re-serialisation of a module that already
|
|
||||||
// went through the optimizer one line above.
|
|
||||||
for (const auto& entry : imageFormatBake.glFormatByUniformName) {
|
|
||||||
if (MG_Util::ShaderTranspiler::ShaderCompiler::WidenedCoreEsslImageFormat(entry.second) != 0) {
|
|
||||||
bakedAWidenableImageFormat = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GL has forty image formats and GLSL ES core has thirteen; the other twenty-seven
|
// GL has forty image formats and GLSL ES core has thirteen; the other twenty-seven
|
||||||
@@ -5650,23 +5651,34 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// have no exact carrier and keep the honest diagnostic
|
// have no exact carrier and keep the honest diagnostic
|
||||||
// CollectImageFormatBakeInputs emits.
|
// CollectImageFormatBakeInputs emits.
|
||||||
//
|
//
|
||||||
|
// A driver that HAS GL_NV_image_formats still needs part of this. SPIRV-Cross throws
|
||||||
|
// for its is_desktop_only_format set when it targets ESSL rather than printing a
|
||||||
|
// token, and the throw loses the stage however willing the driver was - Mesa
|
||||||
|
// advertises the extension and `layout(r8ui) uimage2D` lost its whole program there
|
||||||
|
// until the widening ran for it too. So the driver bit decides HOW MUCH is widened,
|
||||||
|
// never WHETHER.
|
||||||
|
//
|
||||||
// AFTER the bake above, deliberately: a format-less image whose unit holds a non-core
|
// AFTER the bake above, deliberately: a format-less image whose unit holds a non-core
|
||||||
// format is baked with that format and widened here, so both routes end in the same
|
// format is baked with that format and widened here, so both routes end in the same
|
||||||
// place and there is no second widening rule for baked declarations.
|
// place and there is no second widening rule for baked declarations.
|
||||||
//
|
//
|
||||||
// KEY MATERIAL: g_GLESCapabilities.SupportsExtendedImageFormats, which ARMS this -
|
// KEY MATERIAL: g_GLESCapabilities.SupportsExtendedImageFormats, which selects the
|
||||||
// see EsslTranslationKeyInputs::supportsExtendedImageFormats. The pass takes no other
|
// mode - see EsslTranslationKeyInputs::supportsExtendedImageFormats. The pass takes
|
||||||
// input: what it rewrites is a pure function of the module's own declared formats,
|
// no other input: what it rewrites is a pure function of the module's own declared
|
||||||
// and the module is already the largest thing in the L2 key.
|
// formats and that mode, and the module is already the largest thing in the L2 key.
|
||||||
|
// The ARMING flag is deliberately NOT key material: it only decides whether the pass
|
||||||
|
// runs, and the module below is adopted only when the pass actually changed the bytes
|
||||||
|
// - so a program-wide flag that over-arms a stage costs an optimizer round trip and
|
||||||
|
// changes no output.
|
||||||
//
|
//
|
||||||
// DirectVulkan is deliberately not given this: it takes the declared format natively
|
// DirectVulkan is deliberately not given this: it takes the declared format natively
|
||||||
// and resolves the descriptor's view format from the same bind state.
|
// and resolves the descriptor's view format from the same bind state.
|
||||||
Vector<unsigned int> widenedImageFormatSpirv;
|
Vector<unsigned int> widenedImageFormatSpirv;
|
||||||
if (imageFormatWideningArmed &&
|
if (imageFormatBake.declaresWidenableImageFormat &&
|
||||||
(spirvGates.DeclaresWidenableImageFormat || bakedAWidenableImageFormat) &&
|
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::WidenImageFormatsForEssl(
|
MG_Util::ShaderTranspiler::ShaderCompiler::WidenImageFormatsForEssl(
|
||||||
*effectiveSpirv, widenedImageFormatSpirv, enableSpirvValidation) &&
|
*effectiveSpirv, widenedImageFormatSpirv, widenOnlyUnprintableImageFormats,
|
||||||
!widenedImageFormatSpirv.empty()) {
|
enableSpirvValidation) &&
|
||||||
|
!widenedImageFormatSpirv.empty() && widenedImageFormatSpirv != *effectiveSpirv) {
|
||||||
effectiveSpirv = &widenedImageFormatSpirv;
|
effectiveSpirv = &widenedImageFormatSpirv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1398,6 +1398,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Some format in play - declared or baked - is outside the GLSL ES core image
|
// Some format in play - declared or baked - is outside the GLSL ES core image
|
||||||
// format set, so the emitted ESSL needs the GL_NV_image_formats directive.
|
// format set, so the emitted ESSL needs the GL_NV_image_formats directive.
|
||||||
Bool needsExtendedImageFormats = false;
|
Bool needsExtendedImageFormats = false;
|
||||||
|
// Some DECLARED format in play is one WidenImageFormatsForEssl will re-declare in a
|
||||||
|
// core carrier. Answered from the uniform reflection rather than from a module parse
|
||||||
|
// on purpose: the widening is armed on every driver, so a per-stage BuildModule to
|
||||||
|
// find out would land on every stage of every program - which is the cost
|
||||||
|
// SpirvGateFeatures exists to avoid. Program-wide, so it can over-arm a stage that
|
||||||
|
// declares no image; the pass then finds nothing, reports no change, and the caller
|
||||||
|
// keeps the module it already had.
|
||||||
|
Bool declaresWidenableImageFormat = false;
|
||||||
};
|
};
|
||||||
ImageFormatBakeInputs CollectImageFormatBakeInputs(
|
ImageFormatBakeInputs CollectImageFormatBakeInputs(
|
||||||
const MG_State::GLState::ProgramObject& stateProgramObject);
|
const MG_State::GLState::ProgramObject& stateProgramObject);
|
||||||
|
|||||||
@@ -236,18 +236,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImageBindableStorageWidening GetImageBindableStorageWidening(TextureInternalFormat internalFormat) {
|
ImageBindableStorageWidening GetImageBindableStorageWidening(TextureInternalFormat internalFormat) {
|
||||||
// Same arming as WidenImageFormatsForEssl. A driver with GL_NV_image_formats spells
|
|
||||||
// the narrow format natively, and widening the storage behind a shader that still
|
|
||||||
// says `rg32f` would make the two disagree about the texel size.
|
|
||||||
if (g_GLESCapabilities.SupportsExtendedImageFormats) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const GLenum requested = MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat);
|
const GLenum requested = MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat);
|
||||||
const auto carrier = static_cast<GLenum>(
|
const auto carrier = static_cast<GLenum>(
|
||||||
MG_Util::ShaderTranspiler::ShaderCompiler::WidenedCoreEsslImageFormat(requested));
|
MG_Util::ShaderTranspiler::ShaderCompiler::WidenedCoreEsslImageFormat(requested));
|
||||||
if (carrier == 0) {
|
if (carrier == 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
// EXACTLY the arming WidenImageFormatsForEssl uses, and it has to be: the shader, the
|
||||||
|
// storage and the bind must all widen or none of them may, or the shader addresses a
|
||||||
|
// texel size the storage does not have (which every driver tested accepts silently,
|
||||||
|
// reading and writing out of bounds).
|
||||||
|
//
|
||||||
|
// A driver WITH GL_NV_image_formats can spell the narrow format - but only for the
|
||||||
|
// formats SPIRV-Cross will actually print. It throws for its is_desktop_only_format
|
||||||
|
// set instead of emitting a token, and the throw loses the stage whatever the driver
|
||||||
|
// would have accepted: on Mesa, which advertises the extension, `layout(r8ui)
|
||||||
|
// uimage2D` still lost its whole program until the widening ran for it too.
|
||||||
|
if (g_GLESCapabilities.SupportsExtendedImageFormats &&
|
||||||
|
MG_Util::ShaderTranspiler::ShaderCompiler::SpirvCrossCanPrintEsslImageFormat(requested)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
ImageBindableStorageWidening widening;
|
ImageBindableStorageWidening widening;
|
||||||
widening.InternalFormat = carrier;
|
widening.InternalFormat = carrier;
|
||||||
widening.SourceChannels =
|
widening.SourceChannels =
|
||||||
|
|||||||
@@ -3762,7 +3762,7 @@ void main() { imageStore(uni_image, ivec2(0), uvec4(15u)); }
|
|||||||
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(baked));
|
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(baked));
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(baked, widened, true));
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(baked, widened, false, true));
|
||||||
ASSERT_FALSE(widened.empty());
|
ASSERT_FALSE(widened.empty());
|
||||||
const String essl = DecompileToEssl(widened);
|
const String essl = DecompileToEssl(widened);
|
||||||
ASSERT_FALSE(essl.empty());
|
ASSERT_FALSE(essl.empty());
|
||||||
|
|||||||
@@ -319,7 +319,8 @@ TEST(WidenImageFormats, TwoChannelFloatImageBecomesRgba32fWithBothAccessesMasked
|
|||||||
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*enableSpirvValidation=*/true));
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*onlyFormatsSpirvCrossRefusesToPrint=*/false,
|
||||||
|
/*enableSpirvValidation=*/true));
|
||||||
ASSERT_FALSE(widened.empty());
|
ASSERT_FALSE(widened.empty());
|
||||||
EXPECT_TRUE(Validates(widened));
|
EXPECT_TRUE(Validates(widened));
|
||||||
// ...and there is nothing left for a second run to do.
|
// ...and there is nothing left for a second run to do.
|
||||||
@@ -362,7 +363,8 @@ TEST(WidenImageFormats, SingleChannelUnsignedImageBecomesRgba8uiWithBothAccesses
|
|||||||
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
ASSERT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*enableSpirvValidation=*/true));
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*onlyFormatsSpirvCrossRefusesToPrint=*/false,
|
||||||
|
/*enableSpirvValidation=*/true));
|
||||||
ASSERT_FALSE(widened.empty());
|
ASSERT_FALSE(widened.empty());
|
||||||
EXPECT_TRUE(Validates(widened));
|
EXPECT_TRUE(Validates(widened));
|
||||||
|
|
||||||
@@ -406,7 +408,7 @@ TEST(WidenImageFormats, WidenedModulesEmitEsslNamingTheCoreCarrier) {
|
|||||||
<< before.text;
|
<< before.text;
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, true));
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, false, true));
|
||||||
const EsslAttempt after = EmitEssl(widened);
|
const EsslAttempt after = EmitEssl(widened);
|
||||||
ASSERT_TRUE(after.succeeded) << after.error;
|
ASSERT_TRUE(after.succeeded) << after.error;
|
||||||
EXPECT_NE(after.text.find("rgba8ui"), String::npos) << after.text;
|
EXPECT_NE(after.text.find("rgba8ui"), String::npos) << after.text;
|
||||||
@@ -425,7 +427,7 @@ TEST(WidenImageFormats, WidenedModulesEmitEsslNamingTheCoreCarrier) {
|
|||||||
EXPECT_NE(before.text.find("rg32f"), String::npos) << before.text;
|
EXPECT_NE(before.text.find("rg32f"), String::npos) << before.text;
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, true));
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, false, true));
|
||||||
const EsslAttempt after = EmitEssl(widened);
|
const EsslAttempt after = EmitEssl(widened);
|
||||||
ASSERT_TRUE(after.succeeded) << after.error;
|
ASSERT_TRUE(after.succeeded) << after.error;
|
||||||
EXPECT_NE(after.text.find("rgba32f"), String::npos) << after.text;
|
EXPECT_NE(after.text.find("rgba32f"), String::npos) << after.text;
|
||||||
@@ -435,6 +437,55 @@ TEST(WidenImageFormats, WidenedModulesEmitEsslNamingTheCoreCarrier) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The narrow mode, for a driver that HAS GL_NV_image_formats - Mesa, which every software lane
|
||||||
|
// runs on. There the driver can spell rg32f, so widening it would spend two to four times the
|
||||||
|
// texture memory to change nothing; but SPIRV-Cross STILL throws for r8ui rather than printing it,
|
||||||
|
// and the throw loses the stage whatever the driver would have accepted. So the extension narrows
|
||||||
|
// the emulation to its is_desktop_only_format set rather than switching it off.
|
||||||
|
TEST(WidenImageFormats, TheExtensionNarrowsTheWideningToWhatSpirvCrossWillNotPrint) {
|
||||||
|
ASSERT_TRUE(ShaderCompiler::SpirvCrossCanPrintEsslImageFormat(0x8230 /*GL_RG32F*/));
|
||||||
|
ASSERT_FALSE(ShaderCompiler::SpirvCrossCanPrintEsslImageFormat(0x8232 /*GL_R8UI*/));
|
||||||
|
|
||||||
|
{ // rg32f: printable, so the narrow mode leaves it exactly as declared.
|
||||||
|
const Vector<Uint32> spirv = CompileFragment(kRg32fLoadStore);
|
||||||
|
ASSERT_FALSE(spirv.empty());
|
||||||
|
EXPECT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv, false));
|
||||||
|
EXPECT_FALSE(ShaderCompiler::DeclaresWidenableImageFormat(spirv, true));
|
||||||
|
|
||||||
|
Vector<Uint32> widened;
|
||||||
|
ShaderCompiler::WidenImageFormatsForEssl(spirv, widened,
|
||||||
|
/*onlyFormatsSpirvCrossRefusesToPrint=*/true, true);
|
||||||
|
if (!widened.empty()) {
|
||||||
|
const auto types = CollectStorageImageTypes(widened);
|
||||||
|
ASSERT_EQ(types.size(), 1u);
|
||||||
|
EXPECT_EQ(types.front().format, static_cast<Uint32>(spv::ImageFormat::Rg32f));
|
||||||
|
EXPECT_EQ(CollectVectorShuffles(widened).size(), CollectVectorShuffles(spirv).size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ // r8ui: unprintable, so the narrow mode still carries it - and must mask it exactly as
|
||||||
|
// the wide mode does, because the storage and the bind widen with it either way.
|
||||||
|
const Vector<Uint32> spirv = CompileFragment(kR8uiLoadStore);
|
||||||
|
ASSERT_FALSE(spirv.empty());
|
||||||
|
EXPECT_TRUE(ShaderCompiler::DeclaresWidenableImageFormat(spirv, true));
|
||||||
|
|
||||||
|
Vector<Uint32> widened;
|
||||||
|
ASSERT_TRUE(ShaderCompiler::WidenImageFormatsForEssl(
|
||||||
|
spirv, widened, /*onlyFormatsSpirvCrossRefusesToPrint=*/true, true));
|
||||||
|
ASSERT_FALSE(widened.empty());
|
||||||
|
EXPECT_TRUE(Validates(widened));
|
||||||
|
const auto types = CollectStorageImageTypes(widened);
|
||||||
|
ASSERT_EQ(types.size(), 1u);
|
||||||
|
EXPECT_EQ(types.front().format, static_cast<Uint32>(spv::ImageFormat::Rgba8ui));
|
||||||
|
|
||||||
|
const auto shuffles = CollectVectorShuffles(widened);
|
||||||
|
const auto texelIds = CollectImageWriteTexelIds(widened);
|
||||||
|
ASSERT_EQ(texelIds.size(), 1u);
|
||||||
|
const VectorShuffle* storeMask = FindShuffleWithResult(shuffles, texelIds.front());
|
||||||
|
ASSERT_NE(storeMask, nullptr);
|
||||||
|
EXPECT_TRUE(HasComponents(*storeMask, {0u, 5u, 6u, 7u}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(WidenImageFormats, CoreFormatModuleIsHandedBackUntouched) {
|
TEST(WidenImageFormats, CoreFormatModuleIsHandedBackUntouched) {
|
||||||
const Vector<Uint32> spirv = CompileFragment(kCoreFormatLoadStore);
|
const Vector<Uint32> spirv = CompileFragment(kCoreFormatLoadStore);
|
||||||
ASSERT_FALSE(spirv.empty());
|
ASSERT_FALSE(spirv.empty());
|
||||||
@@ -442,7 +493,8 @@ TEST(WidenImageFormats, CoreFormatModuleIsHandedBackUntouched) {
|
|||||||
EXPECT_FALSE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
EXPECT_FALSE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*enableSpirvValidation=*/true);
|
ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*onlyFormatsSpirvCrossRefusesToPrint=*/false,
|
||||||
|
/*enableSpirvValidation=*/true);
|
||||||
if (!widened.empty()) {
|
if (!widened.empty()) {
|
||||||
EXPECT_EQ(CollectVectorShuffles(widened).size(), CollectVectorShuffles(spirv).size())
|
EXPECT_EQ(CollectVectorShuffles(widened).size(), CollectVectorShuffles(spirv).size())
|
||||||
<< "a core-format module must gain no masks";
|
<< "a core-format module must gain no masks";
|
||||||
@@ -466,7 +518,8 @@ TEST(WidenImageFormats, FormatWithoutAnExactCarrierIsLeftAlone) {
|
|||||||
EXPECT_FALSE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
EXPECT_FALSE(ShaderCompiler::DeclaresWidenableImageFormat(spirv));
|
||||||
|
|
||||||
Vector<Uint32> widened;
|
Vector<Uint32> widened;
|
||||||
ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*enableSpirvValidation=*/true);
|
ShaderCompiler::WidenImageFormatsForEssl(spirv, widened, /*onlyFormatsSpirvCrossRefusesToPrint=*/false,
|
||||||
|
/*enableSpirvValidation=*/true);
|
||||||
if (!widened.empty()) {
|
if (!widened.empty()) {
|
||||||
const auto afterTypes = CollectStorageImageTypes(widened);
|
const auto afterTypes = CollectStorageImageTypes(widened);
|
||||||
ASSERT_EQ(afterTypes.size(), 1u);
|
ASSERT_EQ(afterTypes.size(), 1u);
|
||||||
|
|||||||
@@ -728,8 +728,6 @@ namespace MobileGL {
|
|||||||
LowerViewportIndexPass::DeclaresViewportIndexBuiltin(context.get());
|
LowerViewportIndexPass::DeclaresViewportIndexBuiltin(context.get());
|
||||||
features.DeclaresMultisampledImage =
|
features.DeclaresMultisampledImage =
|
||||||
ClampMultisampleFetchPass::DeclaresMultisampledImage(context.get());
|
ClampMultisampleFetchPass::DeclaresMultisampledImage(context.get());
|
||||||
features.DeclaresWidenableImageFormat =
|
|
||||||
WidenImageFormatsPass::DeclaresWidenableImageFormat(context.get());
|
|
||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,10 +774,12 @@ namespace MobileGL {
|
|||||||
|
|
||||||
bool ShaderCompiler::WidenImageFormatsForEssl(const Vector<Uint32>& inputBinary,
|
bool ShaderCompiler::WidenImageFormatsForEssl(const Vector<Uint32>& inputBinary,
|
||||||
Vector<uint32_t>& outputBinary,
|
Vector<uint32_t>& outputBinary,
|
||||||
|
const bool onlyFormatsSpirvCrossRefusesToPrint,
|
||||||
const bool enableSpirvValidation) {
|
const bool enableSpirvValidation) {
|
||||||
using namespace spvtools;
|
using namespace spvtools;
|
||||||
Optimizer optimizer(SPV_ENV_VULKAN_1_1);
|
Optimizer optimizer(SPV_ENV_VULKAN_1_1);
|
||||||
optimizer.RegisterPass(WidenImageFormatsPass::CreateWidenImageFormatsPass());
|
optimizer.RegisterPass(
|
||||||
|
WidenImageFormatsPass::CreateWidenImageFormatsPass(onlyFormatsSpirvCrossRefusesToPrint));
|
||||||
// Two image types that differed only in a format the widening collapses -
|
// Two image types that differed only in a format the widening collapses -
|
||||||
// `layout(rg32f)` and `layout(rgba32f)` in one module - are one type afterwards,
|
// `layout(rg32f)` and `layout(rgba32f)` in one module - are one type afterwards,
|
||||||
// and duplicate non-aggregate type declarations are invalid SPIR-V. This joins
|
// and duplicate non-aggregate type declarations are invalid SPIR-V. This joins
|
||||||
@@ -791,8 +791,10 @@ namespace MobileGL {
|
|||||||
true, enableSpirvValidation);
|
true, enableSpirvValidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderCompiler::DeclaresWidenableImageFormat(const Vector<Uint32>& binary) {
|
bool ShaderCompiler::DeclaresWidenableImageFormat(const Vector<Uint32>& binary,
|
||||||
return WidenImageFormatsPass::DeclaresWidenableImageFormat(binary);
|
const bool onlyFormatsSpirvCrossRefusesToPrint) {
|
||||||
|
return WidenImageFormatsPass::DeclaresWidenableImageFormat(binary,
|
||||||
|
onlyFormatsSpirvCrossRefusesToPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint ShaderCompiler::WidenedCoreEsslImageFormat(Uint glInternalFormat) {
|
Uint ShaderCompiler::WidenedCoreEsslImageFormat(Uint glInternalFormat) {
|
||||||
|
|||||||
@@ -71,10 +71,14 @@ namespace MobileGL {
|
|||||||
// GL_OES_viewport_array AND integer multisample squeezed to 1) the separate
|
// GL_OES_viewport_array AND integer multisample squeezed to 1) the separate
|
||||||
// probes made compile-heavy workloads measurably slower - ReservedNames-class
|
// probes made compile-heavy workloads measurably slower - ReservedNames-class
|
||||||
// CTS cases paid ~10%. Callers with more than one armed gate use this instead.
|
// CTS cases paid ~10%. Callers with more than one armed gate use this instead.
|
||||||
|
// The image-format widening deliberately does NOT ride this probe, even though it
|
||||||
|
// is a module question of exactly the same shape. It is armed on every driver, so
|
||||||
|
// a gate answered from the module would put a BuildModule on every stage of every
|
||||||
|
// program - and the frontend's uniform reflection can answer it for free
|
||||||
|
// (PrgramImpl::ImageFormatBakeInputs::declaresWidenableImageFormat).
|
||||||
struct SpirvGateFeatures {
|
struct SpirvGateFeatures {
|
||||||
Bool WritesViewportIndexOutput = false;
|
Bool WritesViewportIndexOutput = false;
|
||||||
Bool DeclaresMultisampledImage = false;
|
Bool DeclaresMultisampledImage = false;
|
||||||
Bool DeclaresWidenableImageFormat = false;
|
|
||||||
};
|
};
|
||||||
static SpirvGateFeatures ProbeSpirvGateFeatures(const Vector<Uint32>& binary);
|
static SpirvGateFeatures ProbeSpirvGateFeatures(const Vector<Uint32>& binary);
|
||||||
// Replaces an ARRAY vertex input with one input per element at consecutive
|
// Replaces an ARRAY vertex input with one input per element at consecutive
|
||||||
@@ -241,15 +245,21 @@ namespace MobileGL {
|
|||||||
// declared format natively. See WidenImageFormatsPass for the table, for the nine
|
// declared format natively. See WidenImageFormatsPass for the table, for the nine
|
||||||
// formats it deliberately does NOT widen, and for why the texture storage and the
|
// formats it deliberately does NOT widen, and for why the texture storage and the
|
||||||
// glBindImageTexture argument have to move with it.
|
// glBindImageTexture argument have to move with it.
|
||||||
|
// `onlyFormatsSpirvCrossRefusesToPrint` narrows it to the formats that have no
|
||||||
|
// ESSL route even WITH GL_NV_image_formats, because SPIRV-Cross throws for them
|
||||||
|
// rather than printing a token - which is the whole set a driver that advertises
|
||||||
|
// the extension still needs. See WidenImageFormatsPass.
|
||||||
static bool WidenImageFormatsForEssl(const Vector<Uint32>& inputBinary,
|
static bool WidenImageFormatsForEssl(const Vector<Uint32>& inputBinary,
|
||||||
Vector<uint32_t>& outputBinary,
|
Vector<uint32_t>& outputBinary,
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint = false,
|
||||||
bool enableSpirvValidation = false);
|
bool enableSpirvValidation = false);
|
||||||
// Whether the module declares a storage image WidenImageFormatsForEssl would
|
// Whether the module declares a storage image WidenImageFormatsForEssl would
|
||||||
// widen, so the ~every shader that declares none pays no optimizer run. Costs its
|
// widen, under the same mode the run would use. Costs its own module parse, so
|
||||||
// own module parse: the transpile path asks the same question through
|
// the transpile path does NOT gate on this - it answers the question from the
|
||||||
// ProbeSpirvGateFeatures instead, because this gate is armed on every real driver
|
// frontend's uniform reflection instead, for the reason on SpirvGateFeatures.
|
||||||
// and would otherwise put a BuildModule on every stage of every program.
|
// Here for tests and for callers that already hold nothing but the binary.
|
||||||
static bool DeclaresWidenableImageFormat(const Vector<Uint32>& binary);
|
static bool DeclaresWidenableImageFormat(const Vector<Uint32>& binary,
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint = false);
|
||||||
// The core-ESSL GL internal format that carries `glInternalFormat` exactly, or 0
|
// The core-ESSL GL internal format that carries `glInternalFormat` exactly, or 0
|
||||||
// when it needs no widening or cannot be widened exactly. The single source of
|
// when it needs no widening or cannot be widened exactly. The single source of
|
||||||
// truth for all three layers of the emulation: this one answers the shader, and
|
// truth for all three layers of the emulation: this one answers the shader, and
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
#include "WidenImageFormatsPass.h"
|
#include "WidenImageFormatsPass.h"
|
||||||
|
|
||||||
|
// For IsSpirvCrossEsslPrintableFormat: the two passes share one question about the emitter, and
|
||||||
|
// the answer belongs where the rest of the image-format tables already are.
|
||||||
|
#include "BakeImageFormatsPass.h"
|
||||||
|
|
||||||
#include "spirv.hpp"
|
#include "spirv.hpp"
|
||||||
#include "source/opt/build_module.h"
|
#include "source/opt/build_module.h"
|
||||||
#include "source/opt/constants.h"
|
#include "source/opt/constants.h"
|
||||||
@@ -211,12 +215,20 @@ namespace MobileGL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool IsWidenableStorageImageType(const Instruction* type) {
|
Bool IsWidenableStorageImageType(const Instruction* type,
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint) {
|
||||||
if (type == nullptr || type->opcode() != spv::Op::OpTypeImage) return false;
|
if (type == nullptr || type->opcode() != spv::Op::OpTypeImage) return false;
|
||||||
if (type->GetSingleWordInOperand(kImageSampledOperand) != kSampledStorageImage) return false;
|
if (type->GetSingleWordInOperand(kImageSampledOperand) != kSampledStorageImage) return false;
|
||||||
const auto format =
|
const auto format =
|
||||||
static_cast<spv::ImageFormat>(type->GetSingleWordInOperand(kImageFormatOperand));
|
static_cast<spv::ImageFormat>(type->GetSingleWordInOperand(kImageFormatOperand));
|
||||||
return static_cast<Bool>(WideningOfSpirvImageFormat(format));
|
if (!WideningOfSpirvImageFormat(format)) return false;
|
||||||
|
if (onlyFormatsSpirvCrossRefusesToPrint &&
|
||||||
|
BakeImageFormatsPass::IsSpirvCrossEsslPrintableFormat(static_cast<Uint32>(format))) {
|
||||||
|
// The driver can spell this one and the emitter will print it; widening it
|
||||||
|
// would spend two to four times the texture memory to change nothing.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -231,23 +243,25 @@ namespace MobileGL {
|
|||||||
return ChannelsOfSpirvImageFormat(SpirvImageFormatOfGL(glInternalFormat));
|
return ChannelsOfSpirvImageFormat(SpirvImageFormatOfGL(glInternalFormat));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WidenImageFormatsPass::DeclaresWidenableImageFormat(IRContext* context) {
|
bool WidenImageFormatsPass::DeclaresWidenableImageFormat(
|
||||||
|
IRContext* context, const bool onlyFormatsSpirvCrossRefusesToPrint) {
|
||||||
if (context == nullptr) {
|
if (context == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const Instruction& type : context->module()->types_values()) {
|
for (const Instruction& type : context->module()->types_values()) {
|
||||||
if (IsWidenableStorageImageType(&type)) {
|
if (IsWidenableStorageImageType(&type, onlyFormatsSpirvCrossRefusesToPrint)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WidenImageFormatsPass::DeclaresWidenableImageFormat(const Vector<Uint32>& binary) {
|
bool WidenImageFormatsPass::DeclaresWidenableImageFormat(
|
||||||
|
const Vector<Uint32>& binary, const bool onlyFormatsSpirvCrossRefusesToPrint) {
|
||||||
std::unique_ptr<IRContext> context = spvtools::BuildModule(
|
std::unique_ptr<IRContext> context = spvtools::BuildModule(
|
||||||
SPV_ENV_VULKAN_1_1, [](spv_message_level_t, const char*, const spv_position_t&, const char*) {},
|
SPV_ENV_VULKAN_1_1, [](spv_message_level_t, const char*, const spv_position_t&, const char*) {},
|
||||||
binary.data(), binary.size());
|
binary.data(), binary.size());
|
||||||
return DeclaresWidenableImageFormat(context.get());
|
return DeclaresWidenableImageFormat(context.get(), onlyFormatsSpirvCrossRefusesToPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
spvtools::opt::Pass::Status WidenImageFormatsPass::Process() {
|
spvtools::opt::Pass::Status WidenImageFormatsPass::Process() {
|
||||||
@@ -258,7 +272,7 @@ namespace MobileGL {
|
|||||||
// byte-identical - which is every shader but a handful.
|
// byte-identical - which is every shader but a handful.
|
||||||
std::vector<Instruction*> imageTypes;
|
std::vector<Instruction*> imageTypes;
|
||||||
for (Instruction& type : irContext->types_values()) {
|
for (Instruction& type : irContext->types_values()) {
|
||||||
if (IsWidenableStorageImageType(&type)) {
|
if (IsWidenableStorageImageType(&type, m_onlyFormatsSpirvCrossRefusesToPrint)) {
|
||||||
imageTypes.push_back(&type);
|
imageTypes.push_back(&type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -539,8 +553,10 @@ namespace MobileGL {
|
|||||||
return Status::SuccessWithChange;
|
return Status::SuccessWithChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
spvtools::Optimizer::PassToken WidenImageFormatsPass::CreateWidenImageFormatsPass() {
|
spvtools::Optimizer::PassToken WidenImageFormatsPass::CreateWidenImageFormatsPass(
|
||||||
return spvtools::Optimizer::PassToken(spvtools::MakeUnique<WidenImageFormatsPass>());
|
const bool onlyFormatsSpirvCrossRefusesToPrint) {
|
||||||
|
return spvtools::Optimizer::PassToken(
|
||||||
|
spvtools::MakeUnique<WidenImageFormatsPass>(onlyFormatsSpirvCrossRefusesToPrint));
|
||||||
}
|
}
|
||||||
} // namespace ShaderTranspiler
|
} // namespace ShaderTranspiler
|
||||||
} // namespace MG_Util
|
} // namespace MG_Util
|
||||||
|
|||||||
@@ -74,19 +74,39 @@ namespace MobileGL {
|
|||||||
// format from the same bind state, so the module must reach it unchanged.
|
// format from the same bind state, so the module must reach it unchanged.
|
||||||
class WidenImageFormatsPass final : public spvtools::opt::Pass {
|
class WidenImageFormatsPass final : public spvtools::opt::Pass {
|
||||||
public:
|
public:
|
||||||
|
// `onlyFormatsSpirvCrossRefusesToPrint` narrows the pass to the formats that have
|
||||||
|
// no ESSL route even on a driver that DOES advertise GL_NV_image_formats.
|
||||||
|
// SPIRV-Cross's is_desktop_only_format set - r8ui, rg16f, r16i and fifteen others -
|
||||||
|
// makes it THROW for an ESSL target rather than print a token, and the throw takes
|
||||||
|
// the stage with it whatever the driver could have accepted. Mesa is exactly that
|
||||||
|
// case: it advertises the extension, so nothing else needs widening there, and
|
||||||
|
// `layout(r8ui) uimage2D` still lost its whole program until this ran for it.
|
||||||
|
//
|
||||||
|
// Off, the pass widens every format in the table, which is what a driver without
|
||||||
|
// the extension needs. The caller sets it from
|
||||||
|
// g_GLESCapabilities.SupportsExtendedImageFormats, and the SAME rule decides
|
||||||
|
// whether the ES texture storage and the glBindImageTexture argument widen
|
||||||
|
// (TextureImpl::GetImageBindableStorageWidening) - all three have to agree or the
|
||||||
|
// shader addresses a texel size the storage does not have.
|
||||||
|
explicit WidenImageFormatsPass(bool onlyFormatsSpirvCrossRefusesToPrint = false)
|
||||||
|
: m_onlyFormatsSpirvCrossRefusesToPrint(onlyFormatsSpirvCrossRefusesToPrint) {}
|
||||||
|
|
||||||
const char* name() const override { return "mobilegl-widen-image-formats"; }
|
const char* name() const override { return "mobilegl-widen-image-formats"; }
|
||||||
Status Process() override;
|
Status Process() override;
|
||||||
|
|
||||||
// Whether the module declares a storage image whose format this pass would widen,
|
// Whether the module declares a storage image whose format this pass would widen,
|
||||||
// i.e. whether running it could change anything. Answered from a single parse so
|
// i.e. whether running it could change anything. Answered from a single parse so
|
||||||
// the caller can skip the optimizer run entirely - which is every shader but a
|
// the caller can skip the optimizer run entirely - which is every shader but a
|
||||||
// handful.
|
// handful. `onlyFormatsSpirvCrossRefusesToPrint` must match what the run will use,
|
||||||
static bool DeclaresWidenableImageFormat(const Vector<Uint32>& binary);
|
// or the gate answers a question the pass is not being asked.
|
||||||
|
static bool DeclaresWidenableImageFormat(const Vector<Uint32>& binary,
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint = false);
|
||||||
// The same question asked of a module the caller has ALREADY parsed, so a stage
|
// The same question asked of a module the caller has ALREADY parsed, so a stage
|
||||||
// that has to answer several gate questions pays one BuildModule rather than one
|
// that has to answer several gate questions pays one BuildModule rather than one
|
||||||
// per gate - see ShaderCompiler::ProbeSpirvGateFeatures, and the ~10% it cost
|
// per gate - see ShaderCompiler::ProbeSpirvGateFeatures, and the ~10% it cost
|
||||||
// compile-heavy CTS cases when two gates each parsed for themselves.
|
// compile-heavy CTS cases when two gates each parsed for themselves.
|
||||||
static bool DeclaresWidenableImageFormat(spvtools::opt::IRContext* context);
|
static bool DeclaresWidenableImageFormat(spvtools::opt::IRContext* context,
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint = false);
|
||||||
|
|
||||||
// The core-ESSL GL internal format that carries `glInternalFormat` exactly, or 0
|
// The core-ESSL GL internal format that carries `glInternalFormat` exactly, or 0
|
||||||
// when the format needs no widening (it is core already) or cannot be widened
|
// when the format needs no widening (it is core already) or cannot be widened
|
||||||
@@ -99,7 +119,11 @@ namespace MobileGL {
|
|||||||
// forty image formats. The count the widened accesses are masked back to.
|
// forty image formats. The count the widened accesses are masked back to.
|
||||||
static Uint ImageFormatChannelCount(Uint glInternalFormat);
|
static Uint ImageFormatChannelCount(Uint glInternalFormat);
|
||||||
|
|
||||||
static spvtools::Optimizer::PassToken CreateWidenImageFormatsPass();
|
static spvtools::Optimizer::PassToken CreateWidenImageFormatsPass(
|
||||||
|
bool onlyFormatsSpirvCrossRefusesToPrint = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_onlyFormatsSpirvCrossRefusesToPrint = false;
|
||||||
};
|
};
|
||||||
} // namespace ShaderTranspiler
|
} // namespace ShaderTranspiler
|
||||||
} // namespace MG_Util
|
} // namespace MG_Util
|
||||||
|
|||||||
Reference in New Issue
Block a user