mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-15 14:03:23 +09:00
[Feat] (Espryt): forward fragment shading rate to the driver extension
This commit is contained in:
@@ -842,6 +842,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
capabilities.SupportsDrawIndirect,
|
||||
capabilities.SupportsDrawIndirect && capabilities.SupportsBaseInstance,
|
||||
capabilities.SupportsTextureView, capabilities.SupportsTextureCubeMapArray);
|
||||
// Exactly what InitCapabilities forwards into the dynamic parameters: the base
|
||||
// extension and _primitive when the driver has them, _attachment not yet.
|
||||
auto& extensions = MutableRendererInfo().RendererGLInfo.Extensions;
|
||||
if (capabilities.SupportsFragmentShadingRate) {
|
||||
extensions.push_back(E_GL_EXT_fragment_shading_rate);
|
||||
if (capabilities.SupportsFragmentShadingRatePrimitive) {
|
||||
extensions.push_back(E_GL_EXT_fragment_shading_rate_primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -1895,6 +1904,25 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// describe behaviour this backend does not implement.
|
||||
m_dynamicParameters.LayerProvokingVertex = m_GLESCapabilities.LayerProvokingVertex;
|
||||
m_dynamicParameters.ViewportIndexProvokingVertex = m_GLESCapabilities.ViewportIndexProvokingVertex;
|
||||
// GL_EXT_fragment_shading_rate is a straight pass-through: the pipeline rate and the
|
||||
// combiner ops are forwarded per draw (SyncRenderState), gl_ShadingRateEXT and
|
||||
// gl_PrimitiveShadingRateEXT are emitted into the ESSL as the driver's own built-ins, and
|
||||
// the device answers every query. The attachment is not forwarded yet, so it is not
|
||||
// claimed, whatever the driver offers.
|
||||
m_dynamicParameters.SupportsFragmentShadingRate = m_GLESCapabilities.SupportsFragmentShadingRate;
|
||||
m_dynamicParameters.SupportsPrimitiveFragmentShadingRate =
|
||||
m_GLESCapabilities.SupportsFragmentShadingRatePrimitive;
|
||||
m_dynamicParameters.SupportsAttachmentFragmentShadingRate = false;
|
||||
m_dynamicParameters.FragmentShadingRateNonTrivialCombiners =
|
||||
m_GLESCapabilities.FragmentShadingRateNonTrivialCombiners;
|
||||
m_dynamicParameters.FragmentShadingRateWithShaderDepthStencilWrites =
|
||||
m_GLESCapabilities.FragmentShadingRateWithShaderDepthStencilWrites;
|
||||
m_dynamicParameters.FragmentShadingRateWithSampleMask = m_GLESCapabilities.FragmentShadingRateWithSampleMask;
|
||||
m_dynamicParameters.FragmentShadingRatePrimitiveWithMultiViewport =
|
||||
m_GLESCapabilities.FragmentShadingRatePrimitiveWithMultiViewport;
|
||||
for (SizeT i = 0; i < std::size(m_dynamicParameters.FragmentShadingRateMasks); ++i) {
|
||||
m_dynamicParameters.FragmentShadingRateMasks[i] = m_GLESCapabilities.FragmentShadingRateMasks[i];
|
||||
}
|
||||
m_dynamicParameters.MaxViewportWidth = m_GLESCapabilities.MaxViewportWidth;
|
||||
m_dynamicParameters.MaxViewportHeight = m_GLESCapabilities.MaxViewportHeight;
|
||||
m_dynamicParameters.ViewportBoundsRangeMin = m_GLESCapabilities.ViewportBoundsRangeMin;
|
||||
|
||||
@@ -4177,6 +4177,22 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
if (tailSpanDirty && g_GLESCapabilities.SupportsFragmentShadingRate) { // GL_EXT_fragment_shading_rate
|
||||
// The frontend stores the packed rate and op indices; the driver takes the enums.
|
||||
// Only forwarded where the driver has the extension, which is also the only place
|
||||
// the frontend advertised it - so a non-default value cannot exist anywhere else.
|
||||
if (forceFullPush || parameters.ShadingRate != g_syncedRenderStateParameters.ShadingRate) {
|
||||
const GLenum rate = MGUnpackShadingRate(parameters.ShadingRate);
|
||||
g_GLESFuncs.glShadingRateEXT(rate != GL_NONE ? rate : GL_SHADING_RATE_1X1_PIXELS_EXT);
|
||||
}
|
||||
if (forceFullPush ||
|
||||
parameters.ShadingRateCombinerOp0 != g_syncedRenderStateParameters.ShadingRateCombinerOp0 ||
|
||||
parameters.ShadingRateCombinerOp1 != g_syncedRenderStateParameters.ShadingRateCombinerOp1) {
|
||||
g_GLESFuncs.glShadingRateCombinerOpsEXT(MGShadingRateCombinerOpEnum(parameters.ShadingRateCombinerOp0),
|
||||
MGShadingRateCombinerOpEnum(parameters.ShadingRateCombinerOp1));
|
||||
}
|
||||
}
|
||||
|
||||
g_syncedRenderStateVersion = currentRenderStateVersion;
|
||||
// Byte copy, not member copy: it also clones the frontend struct's padding bytes,
|
||||
// which is what lets the span memcmps above answer "unchanged" exactly instead of
|
||||
|
||||
@@ -641,6 +641,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
// absent on plenty of drivers and neither absence is an error.
|
||||
INIT_GLES_FUNC_OPTIONAL(glTextureViewEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glTextureViewOES)
|
||||
// GL_EXT_fragment_shading_rate: extension-only, so absence is not an error.
|
||||
INIT_GLES_FUNC_OPTIONAL(glShadingRateEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glShadingRateCombinerOpsEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glGetFragmentShadingRatesEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glFramebufferShadingRateEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glTexBufferEXT)
|
||||
INIT_GLES_FUNC_OPTIONAL(glTexBufferOES)
|
||||
INIT_GLES_FUNC_OPTIONAL(glTexBufferRangeEXT)
|
||||
@@ -1021,6 +1026,66 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
}
|
||||
}
|
||||
|
||||
// Reads what the driver answers for GL_EXT_fragment_shading_rate once the extension strings have
|
||||
// been matched. The per-sample-count rate lists are folded into masks of the packed encoding
|
||||
// ((log2 w << 2) | log2 h), which is what crosses to the frontend.
|
||||
static void FillInFragmentShadingRateCapabilities(MG_External::GLESCapabilities& caps,
|
||||
const MG_External::GLESFunctionsTable& glesFuncs) {
|
||||
const auto getBoolean = [&](GLenum pname) {
|
||||
GLboolean value = GL_FALSE;
|
||||
glesFuncs.glGetBooleanv(pname, &value);
|
||||
return value == GL_TRUE;
|
||||
};
|
||||
caps.FragmentShadingRateNonTrivialCombiners =
|
||||
getBoolean(GL_FRAGMENT_SHADING_RATE_NON_TRIVIAL_COMBINERS_SUPPORTED_EXT);
|
||||
caps.FragmentShadingRateWithShaderDepthStencilWrites =
|
||||
getBoolean(GL_FRAGMENT_SHADING_RATE_WITH_SHADER_DEPTH_STENCIL_WRITES_SUPPORTED_EXT);
|
||||
caps.FragmentShadingRateWithSampleMask = getBoolean(GL_FRAGMENT_SHADING_RATE_WITH_SAMPLE_MASK_SUPPORTED_EXT);
|
||||
if (caps.SupportsFragmentShadingRatePrimitive) {
|
||||
caps.FragmentShadingRatePrimitiveWithMultiViewport =
|
||||
getBoolean(GL_FRAGMENT_SHADING_RATE_PRIMITIVE_RATE_WITH_MULTI_VIEWPORT_SUPPORTED_EXT);
|
||||
}
|
||||
if (caps.SupportsFragmentShadingRateAttachment) {
|
||||
caps.FragmentShadingRateAttachmentWithDefaultFramebuffer =
|
||||
getBoolean(GL_FRAGMENT_SHADING_RATE_ATTACHMENT_WITH_DEFAULT_FRAMEBUFFER_SUPPORTED_EXT);
|
||||
glesFuncs.glGetIntegerv(GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT,
|
||||
&caps.MinFragmentShadingRateAttachmentTexelWidth);
|
||||
glesFuncs.glGetIntegerv(GL_MIN_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT,
|
||||
&caps.MinFragmentShadingRateAttachmentTexelHeight);
|
||||
glesFuncs.glGetIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_WIDTH_EXT,
|
||||
&caps.MaxFragmentShadingRateAttachmentTexelWidth);
|
||||
glesFuncs.glGetIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_HEIGHT_EXT,
|
||||
&caps.MaxFragmentShadingRateAttachmentTexelHeight);
|
||||
glesFuncs.glGetIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_TEXEL_ASPECT_RATIO_EXT,
|
||||
&caps.MaxFragmentShadingRateAttachmentTexelAspectRatio);
|
||||
glesFuncs.glGetIntegerv(GL_MAX_FRAGMENT_SHADING_RATE_ATTACHMENT_LAYERS_EXT,
|
||||
&caps.MaxFragmentShadingRateAttachmentLayers);
|
||||
}
|
||||
// Table X.1 in enum order, 1X1 .. 4X4, as packed rates.
|
||||
static constexpr Uint8 kPackedByEnumOffset[] = {0x0, 0x1, 0x4, 0x5, 0x2, 0x8, 0x9, 0x6, 0xa};
|
||||
for (SizeT i = 0; i < std::size(caps.FragmentShadingRateMasks); ++i) {
|
||||
GLenum rates[16] = {};
|
||||
GLsizei count = 0;
|
||||
glesFuncs.glGetFragmentShadingRatesEXT(static_cast<GLsizei>(1u << i), 16, &count, rates);
|
||||
Uint16 mask = 0;
|
||||
for (GLsizei r = 0; r < count && r < 16; ++r) {
|
||||
const GLenum offset = rates[r] - GL_SHADING_RATE_1X1_PIXELS_EXT;
|
||||
if (offset < std::size(kPackedByEnumOffset)) mask |= Uint16(1u << kPackedByEnumOffset[offset]);
|
||||
}
|
||||
caps.FragmentShadingRateMasks[i] = mask;
|
||||
}
|
||||
// The queries above are best-effort: a pname a driver does not know only leaves its default.
|
||||
while (glesFuncs.glGetError() != GL_NO_ERROR) {
|
||||
}
|
||||
MGLOG_I("GL_EXT_fragment_shading_rate: primitive=%d attachment=%d nonTrivialCombiners=%d rates(1x)=0x%04x "
|
||||
"rates(4x)=0x%04x attachment texel %dx%d..%dx%d",
|
||||
caps.SupportsFragmentShadingRatePrimitive, caps.SupportsFragmentShadingRateAttachment,
|
||||
caps.FragmentShadingRateNonTrivialCombiners, caps.FragmentShadingRateMasks[0],
|
||||
caps.FragmentShadingRateMasks[2], caps.MinFragmentShadingRateAttachmentTexelWidth,
|
||||
caps.MinFragmentShadingRateAttachmentTexelHeight, caps.MaxFragmentShadingRateAttachmentTexelWidth,
|
||||
caps.MaxFragmentShadingRateAttachmentTexelHeight);
|
||||
}
|
||||
|
||||
Bool FillInGLESCapabilities(MG_External::GLESCapabilities& caps, const MG_External::GLESFunctionsTable& glesFuncs) {
|
||||
if (!glesFuncs.glGetString || !glesFuncs.glGetIntegerv) {
|
||||
MGLOG_E("Required GLES functions are not loaded, cannot query capabilities");
|
||||
@@ -1097,6 +1162,15 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
if (std::strcmp(extension, "GL_OES_texture_view") == 0) {
|
||||
hasOesTextureView = true;
|
||||
}
|
||||
if (std::strcmp(extension, "GL_EXT_fragment_shading_rate") == 0) {
|
||||
caps.SupportsFragmentShadingRate = true;
|
||||
}
|
||||
if (std::strcmp(extension, "GL_EXT_fragment_shading_rate_primitive") == 0) {
|
||||
caps.SupportsFragmentShadingRatePrimitive = true;
|
||||
}
|
||||
if (std::strcmp(extension, "GL_EXT_fragment_shading_rate_attachment") == 0) {
|
||||
caps.SupportsFragmentShadingRateAttachment = true;
|
||||
}
|
||||
if (std::strcmp(extension, "GL_EXT_texture_buffer") == 0) {
|
||||
hasExtTextureBuffer = true;
|
||||
}
|
||||
@@ -1183,6 +1257,20 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
MGLOG_I("MOBILEGL_DISABLE_TEXTURE_VIEW is set; reporting no EXT/OES_texture_view support");
|
||||
caps.SupportsTextureView = false;
|
||||
}
|
||||
// Each companion builds on the base extension, and each needs the entry points it brings;
|
||||
// the strings alone never count (see AcquireGLESFunctions on stub pointers).
|
||||
caps.SupportsFragmentShadingRate = caps.SupportsFragmentShadingRate &&
|
||||
glesFuncs.glShadingRateEXT != nullptr &&
|
||||
glesFuncs.glShadingRateCombinerOpsEXT != nullptr &&
|
||||
glesFuncs.glGetFragmentShadingRatesEXT != nullptr;
|
||||
caps.SupportsFragmentShadingRatePrimitive =
|
||||
caps.SupportsFragmentShadingRate && caps.SupportsFragmentShadingRatePrimitive;
|
||||
caps.SupportsFragmentShadingRateAttachment = caps.SupportsFragmentShadingRate &&
|
||||
caps.SupportsFragmentShadingRateAttachment &&
|
||||
glesFuncs.glFramebufferShadingRateEXT != nullptr;
|
||||
if (caps.SupportsFragmentShadingRate) {
|
||||
FillInFragmentShadingRateCapabilities(caps, glesFuncs);
|
||||
}
|
||||
// Core from ES 3.2 on, so an extension string is not required there; below 3.2 the
|
||||
// extension is, and the pointer still has to have resolved either way.
|
||||
const Bool esAtLeast32 = caps.GLESVersion.Major > 3 ||
|
||||
|
||||
@@ -619,6 +619,13 @@ namespace MobileGL {
|
||||
GL_FUNC_TYPEDEF(void, glTextureViewOES, GLuint texture, GLenum target, GLuint origtexture,
|
||||
GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer,
|
||||
GLuint numlayers)
|
||||
// GL_EXT_fragment_shading_rate (+ _attachment). Extension-only in every ES version.
|
||||
GL_FUNC_TYPEDEF(void, glShadingRateEXT, GLenum rate)
|
||||
GL_FUNC_TYPEDEF(void, glShadingRateCombinerOpsEXT, GLenum combinerOp0, GLenum combinerOp1)
|
||||
GL_FUNC_TYPEDEF(void, glGetFragmentShadingRatesEXT, GLsizei samples, GLsizei maxCount, GLsizei* count,
|
||||
GLenum* shadingRates)
|
||||
GL_FUNC_TYPEDEF(void, glFramebufferShadingRateEXT, GLenum target, GLenum attachment, GLuint texture,
|
||||
GLint baseLayer, GLsizei numLayers, GLsizei texelWidth, GLsizei texelHeight)
|
||||
GL_FUNC_TYPEDEF(void, glTexBufferEXT, GLenum target, GLenum internalformat, GLuint buffer)
|
||||
GL_FUNC_TYPEDEF(void, glTexBufferOES, GLenum target, GLenum internalformat, GLuint buffer)
|
||||
GL_FUNC_TYPEDEF(void, glTexBufferRangeEXT, GLenum target, GLenum internalformat, GLuint buffer,
|
||||
@@ -1040,6 +1047,10 @@ namespace MobileGL {
|
||||
GL_FUNC_DECL(glTexBufferRange)
|
||||
GL_FUNC_DECL(glTextureViewEXT)
|
||||
GL_FUNC_DECL(glTextureViewOES)
|
||||
GL_FUNC_DECL(glShadingRateEXT)
|
||||
GL_FUNC_DECL(glShadingRateCombinerOpsEXT)
|
||||
GL_FUNC_DECL(glGetFragmentShadingRatesEXT)
|
||||
GL_FUNC_DECL(glFramebufferShadingRateEXT)
|
||||
GL_FUNC_DECL(glTexBufferEXT)
|
||||
GL_FUNC_DECL(glTexBufferOES)
|
||||
GL_FUNC_DECL(glTexBufferRangeEXT)
|
||||
@@ -1111,6 +1122,27 @@ namespace MobileGL {
|
||||
// through the other). Gate on this, never on the entry points: eglGetProcAddress
|
||||
// hands back live-looking stubs (see AcquireGLESFunctions).
|
||||
Bool SupportsTextureView = false;
|
||||
// GL_EXT_fragment_shading_rate and its _primitive / _attachment companions, with what the
|
||||
// driver answers for them. Extension-only in every ES version; each flag also requires
|
||||
// the entry points that extension brings, and _primitive / _attachment require the base
|
||||
// one. The values below are meaningful only when their flag is set.
|
||||
Bool SupportsFragmentShadingRate = false;
|
||||
Bool SupportsFragmentShadingRatePrimitive = false;
|
||||
Bool SupportsFragmentShadingRateAttachment = false;
|
||||
Bool FragmentShadingRateNonTrivialCombiners = false;
|
||||
Bool FragmentShadingRateWithShaderDepthStencilWrites = false;
|
||||
Bool FragmentShadingRateWithSampleMask = false;
|
||||
Bool FragmentShadingRatePrimitiveWithMultiViewport = false;
|
||||
Bool FragmentShadingRateAttachmentWithDefaultFramebuffer = false;
|
||||
// glGetFragmentShadingRatesEXT for 1, 2, 4 .. 64 samples, as a mask of packed rates
|
||||
// (see MG_Backend::DynamicBackendParameters::FragmentShadingRateMasks).
|
||||
Uint16 FragmentShadingRateMasks[7] = {};
|
||||
Int MinFragmentShadingRateAttachmentTexelWidth = 0;
|
||||
Int MinFragmentShadingRateAttachmentTexelHeight = 0;
|
||||
Int MaxFragmentShadingRateAttachmentTexelWidth = 0;
|
||||
Int MaxFragmentShadingRateAttachmentTexelHeight = 0;
|
||||
Int MaxFragmentShadingRateAttachmentTexelAspectRatio = 0;
|
||||
Int MaxFragmentShadingRateAttachmentLayers = 0;
|
||||
// Which spelling of buffer-texture support the host driver has. Desktop GL makes buffer
|
||||
// textures core from 3.1 on, so the frontend advertises them unconditionally and an app
|
||||
// may call glTexBuffer at any time; ES only gained them in 3.2, and before that only
|
||||
|
||||
Reference in New Issue
Block a user