mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 14:18:31 +09:00
[Fix, Test] (BackendLoader, DirectGLES, DirectVulkan, GLImpl): answer the layer and viewport-index provoking-vertex conventions from the backend
This commit is contained in:
@@ -384,6 +384,20 @@ namespace MobileGL {
|
|||||||
// hand glslang a workable gl_MaxClipDistances.
|
// hand glslang a workable gl_MaxClipDistances.
|
||||||
Int MaxClipDistances = 8;
|
Int MaxClipDistances = 8;
|
||||||
Int MaxViewports = 16;
|
Int MaxViewports = 16;
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX / GL_VIEWPORT_INDEX_PROVOKING_VERTEX: which vertex of a
|
||||||
|
// primitive supplies gl_Layer and gl_ViewportIndex. GL 4.6 table 23.65 makes
|
||||||
|
// GL_UNDEFINED_VERTEX a legal answer for both, and it is the honest default - naming
|
||||||
|
// a convention is a statement about behaviour, so a backend that does not pin one
|
||||||
|
// must not claim it does. DirectGLES fills the layer one from the ES 3.2 query and
|
||||||
|
// the viewport one from GL_OES_viewport_array, and leaves UNDEFINED where the
|
||||||
|
// capability is absent: without the viewport array extension only viewport 0 is ever
|
||||||
|
// rasterized, so no convention selects anything. DirectVulkan keeps UNDEFINED for
|
||||||
|
// both - which vertex provokes is decided per pipeline by
|
||||||
|
// VulkanRenderer::SelectProvokingVertexMode out of VK_EXT_provoking_vertex,
|
||||||
|
// provokingVertexModePerPipeline and the topology, so no single convention is true
|
||||||
|
// of the backend.
|
||||||
|
GLenum LayerProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
|
GLenum ViewportIndexProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
Int MaxViewportWidth = 16384;
|
Int MaxViewportWidth = 16384;
|
||||||
Int MaxViewportHeight = 16384;
|
Int MaxViewportHeight = 16384;
|
||||||
Float ViewportBoundsRangeMin = 0.0f;
|
Float ViewportBoundsRangeMin = 0.0f;
|
||||||
|
|||||||
@@ -1336,6 +1336,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_dynamicParameters.MaxColorAttachments = m_GLESCapabilities.MaxColorAttachments;
|
m_dynamicParameters.MaxColorAttachments = m_GLESCapabilities.MaxColorAttachments;
|
||||||
m_dynamicParameters.MaxClipDistances = m_GLESCapabilities.MaxClipDistances;
|
m_dynamicParameters.MaxClipDistances = m_GLESCapabilities.MaxClipDistances;
|
||||||
m_dynamicParameters.MaxViewports = m_GLESCapabilities.MaxViewports;
|
m_dynamicParameters.MaxViewports = m_GLESCapabilities.MaxViewports;
|
||||||
|
// Whatever the driver said about which vertex supplies gl_Layer, and GL_UNDEFINED_VERTEX
|
||||||
|
// for gl_ViewportIndex on every driver without GL_OES_viewport_array - which is both test
|
||||||
|
// devices. That is not a shortfall being hidden: without the extension only viewport 0 is
|
||||||
|
// ever rasterized, so no vertex "selects" a viewport index and naming a convention would
|
||||||
|
// describe behaviour this backend does not implement.
|
||||||
|
m_dynamicParameters.LayerProvokingVertex = m_GLESCapabilities.LayerProvokingVertex;
|
||||||
|
m_dynamicParameters.ViewportIndexProvokingVertex = m_GLESCapabilities.ViewportIndexProvokingVertex;
|
||||||
m_dynamicParameters.MaxViewportWidth = m_GLESCapabilities.MaxViewportWidth;
|
m_dynamicParameters.MaxViewportWidth = m_GLESCapabilities.MaxViewportWidth;
|
||||||
m_dynamicParameters.MaxViewportHeight = m_GLESCapabilities.MaxViewportHeight;
|
m_dynamicParameters.MaxViewportHeight = m_GLESCapabilities.MaxViewportHeight;
|
||||||
m_dynamicParameters.ViewportBoundsRangeMin = m_GLESCapabilities.ViewportBoundsRangeMin;
|
m_dynamicParameters.ViewportBoundsRangeMin = m_GLESCapabilities.ViewportBoundsRangeMin;
|
||||||
|
|||||||
@@ -912,6 +912,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_dynamicParameters.MaxClipDistances =
|
m_dynamicParameters.MaxClipDistances =
|
||||||
m_vulkanCaps.SupportsShaderClipDistance ? std::max(m_vulkanCaps.MaxClipDistances, 0) : 0;
|
m_vulkanCaps.SupportsShaderClipDistance ? std::max(m_vulkanCaps.MaxClipDistances, 0) : 0;
|
||||||
m_dynamicParameters.MaxViewports = m_vulkanCaps.MaxViewports;
|
m_dynamicParameters.MaxViewports = m_vulkanCaps.MaxViewports;
|
||||||
|
// Assigned explicitly rather than left to the struct's defaults, like every other
|
||||||
|
// parameter here, so a second fill cannot inherit a stale value. GL_UNDEFINED_VERTEX is
|
||||||
|
// the truthful answer for DirectVulkan and a legal one (GL 4.6 table 23.65): which vertex
|
||||||
|
// provokes is chosen per pipeline by VulkanRenderer::SelectProvokingVertexMode out of
|
||||||
|
// VK_EXT_provoking_vertex, provokingVertexModePerPipeline and the topology, so there is no
|
||||||
|
// one convention to name. Vulkan's own default is FIRST, which is the opposite of the
|
||||||
|
// GL_LAST_VERTEX_CONVENTION this used to claim unconditionally.
|
||||||
|
m_dynamicParameters.LayerProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
|
m_dynamicParameters.ViewportIndexProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
m_dynamicParameters.MaxViewportWidth = m_vulkanCaps.MaxViewportWidth;
|
m_dynamicParameters.MaxViewportWidth = m_vulkanCaps.MaxViewportWidth;
|
||||||
m_dynamicParameters.MaxViewportHeight = m_vulkanCaps.MaxViewportHeight;
|
m_dynamicParameters.MaxViewportHeight = m_vulkanCaps.MaxViewportHeight;
|
||||||
m_dynamicParameters.ViewportBoundsRangeMin = m_vulkanCaps.ViewportBoundsRangeMin;
|
m_dynamicParameters.ViewportBoundsRangeMin = m_vulkanCaps.ViewportBoundsRangeMin;
|
||||||
|
|||||||
@@ -1572,9 +1572,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_LINE_WIDTH:
|
case GL_LINE_WIDTH:
|
||||||
*params = static_cast<GLint>(MG_State::pGLContext->GetLineWidth());
|
*params = static_cast<GLint>(MG_State::pGLContext->GetLineWidth());
|
||||||
return;
|
return;
|
||||||
case GL_LAYER_PROVOKING_VERTEX:
|
|
||||||
*params = GL_LAST_VERTEX_CONVENTION;
|
|
||||||
return;
|
|
||||||
case GL_LOGIC_OP_MODE:
|
case GL_LOGIC_OP_MODE:
|
||||||
*params = static_cast<GLint>(MG_Util::ConvertLogicOperationToGLEnum(MG_State::pGLContext->GetLogicOp()));
|
*params = static_cast<GLint>(MG_Util::ConvertLogicOperationToGLEnum(MG_State::pGLContext->GetLogicOp()));
|
||||||
return;
|
return;
|
||||||
@@ -2117,9 +2114,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
params[3] = vp.w();
|
params[3] = vp.w();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case GL_VIEWPORT_INDEX_PROVOKING_VERTEX:
|
|
||||||
*params = GL_LAST_VERTEX_CONVENTION;
|
|
||||||
return;
|
|
||||||
case GL_MAX_ELEMENT_INDEX:
|
case GL_MAX_ELEMENT_INDEX:
|
||||||
*params = 1024 * 1024; // TODO
|
*params = 1024 * 1024; // TODO
|
||||||
return;
|
return;
|
||||||
@@ -2207,6 +2201,20 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_MAX_CLIP_DISTANCES:
|
case GL_MAX_CLIP_DISTANCES:
|
||||||
*params = dynamicParameters.MaxClipDistances;
|
*params = dynamicParameters.MaxClipDistances;
|
||||||
break;
|
break;
|
||||||
|
// Both were a hard-coded GL_LAST_VERTEX_CONVENTION, derived from nothing. GL 4.6 table
|
||||||
|
// 23.65 permits GL_UNDEFINED_VERTEX for either, and that is what the backends report
|
||||||
|
// wherever they do not actually pin a convention - claiming one is a statement about
|
||||||
|
// which vertex of a primitive supplies gl_Layer / gl_ViewportIndex, and DirectGLES
|
||||||
|
// rasterizes only viewport 0 on a driver without GL_OES_viewport_array while
|
||||||
|
// DirectVulkan picks its provoking mode per pipeline. KHR-GLxx.viewport_array.query
|
||||||
|
// accepts all four values, and .provoking_vertex - which failed on both devices, in
|
||||||
|
// OPPOSITE directions - stops verifying as soon as either answer is undefined.
|
||||||
|
case GL_LAYER_PROVOKING_VERTEX:
|
||||||
|
*params = static_cast<GLint>(dynamicParameters.LayerProvokingVertex);
|
||||||
|
break;
|
||||||
|
case GL_VIEWPORT_INDEX_PROVOKING_VERTEX:
|
||||||
|
*params = static_cast<GLint>(dynamicParameters.ViewportIndexProvokingVertex);
|
||||||
|
break;
|
||||||
case GL_MAX_COLOR_TEXTURE_SAMPLES:
|
case GL_MAX_COLOR_TEXTURE_SAMPLES:
|
||||||
*params = std::max(dynamicParameters.MaxColorTextureSamples, GetAdvertisedMaxSamples());
|
*params = std::max(dynamicParameters.MaxColorTextureSamples, GetAdvertisedMaxSamples());
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ namespace {
|
|||||||
GLint maxViewports = 32;
|
GLint maxViewports = 32;
|
||||||
GLint viewportSubpixelBits = 8;
|
GLint viewportSubpixelBits = 8;
|
||||||
bool viewportArrayLimitsQueried = false;
|
bool viewportArrayLimitsQueried = false;
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX is ES 3.2 core; GL_VIEWPORT_INDEX_PROVOKING_VERTEX comes with
|
||||||
|
// GL_OES_viewport_array. Both must go unasked where they do not exist, and a driver answer
|
||||||
|
// outside the four legal conventions must not be forwarded as one.
|
||||||
|
GLint layerProvokingVertex = GL_FIRST_VERTEX_CONVENTION;
|
||||||
|
GLint viewportIndexProvokingVertex = GL_LAST_VERTEX_CONVENTION;
|
||||||
|
bool layerProvokingVertexQueried = false;
|
||||||
// A driver rejecting one of the UNCONDITIONAL probes. GL_SMOOTH_LINE_WIDTH_RANGE is the
|
// A driver rejecting one of the UNCONDITIONAL probes. GL_SMOOTH_LINE_WIDTH_RANGE is the
|
||||||
// realistic one - it is desktop-only state that every GLES driver refuses - and it stands
|
// realistic one - it is desktop-only state that every GLES driver refuses - and it stands
|
||||||
// in for the whole run: whatever it leaves behind must not reach the application.
|
// in for the whole run: whatever it leaves behind must not reach the application.
|
||||||
@@ -195,6 +201,14 @@ namespace {
|
|||||||
g_fake.viewportArrayLimitsQueried = true;
|
g_fake.viewportArrayLimitsQueried = true;
|
||||||
*data = g_fake.viewportSubpixelBits;
|
*data = g_fake.viewportSubpixelBits;
|
||||||
break;
|
break;
|
||||||
|
case GL_VIEWPORT_INDEX_PROVOKING_VERTEX:
|
||||||
|
g_fake.viewportArrayLimitsQueried = true;
|
||||||
|
*data = g_fake.viewportIndexProvokingVertex;
|
||||||
|
break;
|
||||||
|
case GL_LAYER_PROVOKING_VERTEX:
|
||||||
|
g_fake.layerProvokingVertexQueried = true;
|
||||||
|
*data = g_fake.layerProvokingVertex;
|
||||||
|
break;
|
||||||
case GL_MAX_COLOR_TEXTURE_SAMPLES:
|
case GL_MAX_COLOR_TEXTURE_SAMPLES:
|
||||||
case GL_MAX_DEPTH_TEXTURE_SAMPLES:
|
case GL_MAX_DEPTH_TEXTURE_SAMPLES:
|
||||||
case GL_MAX_FRAMEBUFFER_SAMPLES:
|
case GL_MAX_FRAMEBUFFER_SAMPLES:
|
||||||
@@ -782,6 +796,62 @@ TEST(ViewportArrayCapabilities, TheLimitsAreOnlyAskedForWhenTheExtensionIsPresen
|
|||||||
EXPECT_EQ(withCaps.ViewportSubpixelBits, g_fake.viewportSubpixelBits);
|
EXPECT_EQ(withCaps.ViewportSubpixelBits, g_fake.viewportSubpixelBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX and GL_VIEWPORT_INDEX_PROVOKING_VERTEX name which vertex of a
|
||||||
|
// primitive supplies gl_Layer and gl_ViewportIndex. MobileGL used to answer a hard-coded
|
||||||
|
// GL_LAST_VERTEX_CONVENTION for both, derived from nothing, and got it wrong on both test devices
|
||||||
|
// in OPPOSITE directions. GL_UNDEFINED_VERTEX is a legal answer (GL 4.6 table 23.65) and it is
|
||||||
|
// the honest one wherever the capability that would give the convention meaning is absent.
|
||||||
|
TEST(ProvokingVertexConventions, AreTakenFromTheDriverOnlyWhereThePnameExists) {
|
||||||
|
const auto funcs = MakeFakeGLESFunctions();
|
||||||
|
|
||||||
|
// ES 3.1, no viewport array: neither pname exists, so neither is asked for.
|
||||||
|
ResetFakeDriver();
|
||||||
|
g_fake.maxVertexSsboBlocks = 0;
|
||||||
|
MobileGL::MG_External::GLESCapabilities es31Caps;
|
||||||
|
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(es31Caps, funcs));
|
||||||
|
EXPECT_FALSE(g_fake.layerProvokingVertexQueried);
|
||||||
|
EXPECT_EQ(es31Caps.LayerProvokingVertex, static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
EXPECT_EQ(es31Caps.ViewportIndexProvokingVertex, static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
|
||||||
|
// ES 3.2 with the viewport array: both exist and both driver answers come through verbatim.
|
||||||
|
ResetFakeDriver();
|
||||||
|
g_fake.maxVertexSsboBlocks = 0;
|
||||||
|
g_fake.glesMinorVersion = 2;
|
||||||
|
g_fake.extensions.emplace_back("GL_OES_viewport_array");
|
||||||
|
MobileGL::MG_External::GLESCapabilities es32Caps;
|
||||||
|
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(es32Caps, funcs));
|
||||||
|
EXPECT_TRUE(g_fake.layerProvokingVertexQueried);
|
||||||
|
EXPECT_EQ(es32Caps.LayerProvokingVertex, static_cast<GLenum>(GL_FIRST_VERTEX_CONVENTION));
|
||||||
|
EXPECT_EQ(es32Caps.ViewportIndexProvokingVertex, static_cast<GLenum>(GL_LAST_VERTEX_CONVENTION));
|
||||||
|
|
||||||
|
// ES 3.2 WITHOUT the viewport array - the shape of both test devices. The layer convention is
|
||||||
|
// real and comes from the driver; the viewport-index one describes a selection that never
|
||||||
|
// happens, because only viewport 0 is ever rasterized, and stays undefined.
|
||||||
|
ResetFakeDriver();
|
||||||
|
g_fake.maxVertexSsboBlocks = 0;
|
||||||
|
g_fake.glesMinorVersion = 2;
|
||||||
|
MobileGL::MG_External::GLESCapabilities deviceLikeCaps;
|
||||||
|
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(deviceLikeCaps, funcs));
|
||||||
|
EXPECT_EQ(deviceLikeCaps.LayerProvokingVertex, static_cast<GLenum>(GL_FIRST_VERTEX_CONVENTION));
|
||||||
|
EXPECT_EQ(deviceLikeCaps.ViewportIndexProvokingVertex, static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
}
|
||||||
|
|
||||||
|
// A driver answering something that is not one of the four legal conventions must not have it
|
||||||
|
// forwarded as one: GL_UNDEFINED_VERTEX describes "MobileGL cannot tell you" exactly.
|
||||||
|
TEST(ProvokingVertexConventions, AnIllegalDriverAnswerBecomesUndefined) {
|
||||||
|
ResetFakeDriver();
|
||||||
|
g_fake.maxVertexSsboBlocks = 0;
|
||||||
|
g_fake.glesMinorVersion = 2;
|
||||||
|
g_fake.layerProvokingVertex = 0x1234;
|
||||||
|
const auto funcs = MakeFakeGLESFunctions();
|
||||||
|
|
||||||
|
MobileGL::MG_External::GLESCapabilities caps;
|
||||||
|
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(caps, funcs));
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_fake.layerProvokingVertexQueried);
|
||||||
|
EXPECT_EQ(caps.LayerProvokingVertex, static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
}
|
||||||
|
|
||||||
// The multisample ceilings are ES 3.1 state; a driver that answers zero - or an older context
|
// The multisample ceilings are ES 3.1 state; a driver that answers zero - or an older context
|
||||||
// that answers nothing - must not have that reach GL_Getter, which would then reject the sample
|
// that answers nothing - must not have that reach GL_Getter, which would then reject the sample
|
||||||
// count it just advertised.
|
// count it just advertised.
|
||||||
|
|||||||
@@ -665,6 +665,33 @@ TEST(DirectVulkanSanity, GatesClipDistancesOnTheShaderClipDistanceFeature) {
|
|||||||
EXPECT_EQ(backend.GetDynamicParameters().MaxClipDistances, 8);
|
EXPECT_EQ(backend.GetDynamicParameters().MaxClipDistances, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX / GL_VIEWPORT_INDEX_PROVOKING_VERTEX were a hard-coded
|
||||||
|
// GL_LAST_VERTEX_CONVENTION for both backends, derived from nothing, and wrong on both test
|
||||||
|
// devices in opposite directions. DirectGLES now forwards what its loader resolved; DirectVulkan
|
||||||
|
// reports GL_UNDEFINED_VERTEX, which GL 4.6 table 23.65 permits and which is what the backend
|
||||||
|
// honestly implements - the provoking mode is chosen per pipeline out of VK_EXT_provoking_vertex,
|
||||||
|
// provokingVertexModePerPipeline and the topology.
|
||||||
|
TEST(ProvokingVertexConventions, EachBackendReportsWhatItActuallyPins) {
|
||||||
|
using namespace MobileGL;
|
||||||
|
|
||||||
|
MG_Backend::DirectGLES::BackendObject_DirectGLES glesBackend;
|
||||||
|
MG_External::GLESCapabilities glesCaps;
|
||||||
|
glesCaps.LayerProvokingVertex = GL_FIRST_VERTEX_CONVENTION;
|
||||||
|
glesCaps.ViewportIndexProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
|
glesBackend.ApplyGLESCapabilitiesForTesting(glesCaps);
|
||||||
|
EXPECT_EQ(glesBackend.GetDynamicParameters().LayerProvokingVertex,
|
||||||
|
static_cast<GLenum>(GL_FIRST_VERTEX_CONVENTION));
|
||||||
|
EXPECT_EQ(glesBackend.GetDynamicParameters().ViewportIndexProvokingVertex,
|
||||||
|
static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
|
||||||
|
MG_Backend::DirectVulkan::BackendObject_DirectVulkan vkBackend;
|
||||||
|
MG_External::VulkanCapabilities vkCaps;
|
||||||
|
vkBackend.ApplyVulkanCapabilitiesForTesting(vkCaps);
|
||||||
|
EXPECT_EQ(vkBackend.GetDynamicParameters().LayerProvokingVertex, static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
EXPECT_EQ(vkBackend.GetDynamicParameters().ViewportIndexProvokingVertex,
|
||||||
|
static_cast<GLenum>(GL_UNDEFINED_VERTEX));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FragmentInterpolationCapabilities, PlumbsGLESAndBothVulkanPropertyPaths) {
|
TEST(FragmentInterpolationCapabilities, PlumbsGLESAndBothVulkanPropertyPaths) {
|
||||||
using namespace MobileGL;
|
using namespace MobileGL;
|
||||||
|
|
||||||
|
|||||||
@@ -831,6 +831,35 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
return includesBase;
|
return includesBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GL 4.6 table 23.65 admits exactly four answers for GL_LAYER_PROVOKING_VERTEX and
|
||||||
|
// GL_VIEWPORT_INDEX_PROVOKING_VERTEX. Anything else means the driver wrote something MobileGL
|
||||||
|
// cannot forward as a convention, and GL_UNDEFINED_VERTEX - a legal answer, not a placeholder
|
||||||
|
// - is the accurate thing to say about it.
|
||||||
|
static GLenum NormalizeProvokingVertexConvention(GLint driverValue) {
|
||||||
|
switch (static_cast<GLenum>(driverValue)) {
|
||||||
|
case GL_FIRST_VERTEX_CONVENTION:
|
||||||
|
case GL_LAST_VERTEX_CONVENTION:
|
||||||
|
case GL_PROVOKING_VERTEX:
|
||||||
|
case GL_UNDEFINED_VERTEX:
|
||||||
|
return static_cast<GLenum>(driverValue);
|
||||||
|
default:
|
||||||
|
return GL_UNDEFINED_VERTEX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* ProvokingVertexConventionName(GLenum convention) {
|
||||||
|
switch (convention) {
|
||||||
|
case GL_FIRST_VERTEX_CONVENTION:
|
||||||
|
return "GL_FIRST_VERTEX_CONVENTION";
|
||||||
|
case GL_LAST_VERTEX_CONVENTION:
|
||||||
|
return "GL_LAST_VERTEX_CONVENTION";
|
||||||
|
case GL_PROVOKING_VERTEX:
|
||||||
|
return "GL_PROVOKING_VERTEX";
|
||||||
|
default:
|
||||||
|
return "GL_UNDEFINED_VERTEX";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Bool FillInGLESCapabilities(MG_External::GLESCapabilities& caps, const MG_External::GLESFunctionsTable& glesFuncs) {
|
Bool FillInGLESCapabilities(MG_External::GLESCapabilities& caps, const MG_External::GLESFunctionsTable& glesFuncs) {
|
||||||
if (!glesFuncs.glGetString || !glesFuncs.glGetIntegerv) {
|
if (!glesFuncs.glGetString || !glesFuncs.glGetIntegerv) {
|
||||||
MGLOG_E("Required GLES functions are not loaded, cannot query capabilities");
|
MGLOG_E("Required GLES functions are not loaded, cannot query capabilities");
|
||||||
@@ -1073,6 +1102,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
// clipping program silently rendered nothing. The guarded probe below only ever widens it.
|
// clipping program silently rendered nothing. The guarded probe below only ever widens it.
|
||||||
GLint maxClipDistances = 0;
|
GLint maxClipDistances = 0;
|
||||||
GLint maxViewports = 16;
|
GLint maxViewports = 16;
|
||||||
|
// GL_UNDEFINED_VERTEX is what stands when the probes below cannot run, and it is a legal
|
||||||
|
// answer rather than a placeholder: with neither geometry shaders nor a viewport array
|
||||||
|
// there is no layered or multi-viewport draw for a convention to describe.
|
||||||
|
GLenum layerProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
|
GLenum viewportIndexProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
GLfloat minFragmentInterpolationOffset = -0.5f;
|
GLfloat minFragmentInterpolationOffset = -0.5f;
|
||||||
GLfloat maxFragmentInterpolationOffset = 0.4375f;
|
GLfloat maxFragmentInterpolationOffset = 0.4375f;
|
||||||
GLint fragmentInterpolationOffsetBits = 4;
|
GLint fragmentInterpolationOffsetBits = 4;
|
||||||
@@ -1263,6 +1297,21 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxViewportDims);
|
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxViewportDims);
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX is ES 3.2 core (it arrives with geometry shaders, which is
|
||||||
|
// what gl_Layer needs). Ask the driver where the pname exists rather than asserting a
|
||||||
|
// convention: it is a statement about which vertex of a primitive supplies gl_Layer, and
|
||||||
|
// MobileGL forwards the geometry stage to the driver rather than implementing the
|
||||||
|
// selection itself, so the driver's answer IS MobileGL's answer. Below ES 3.2 there are
|
||||||
|
// no layered draws to have a convention for and GL_UNDEFINED_VERTEX stands, which GL 4.6
|
||||||
|
// table 23.65 explicitly permits.
|
||||||
|
if (esAtLeast32) {
|
||||||
|
GLint driverLayerConvention = static_cast<GLint>(GL_UNDEFINED_VERTEX);
|
||||||
|
drainErrors();
|
||||||
|
glesFuncs.glGetIntegerv(GL_LAYER_PROVOKING_VERTEX, &driverLayerConvention);
|
||||||
|
if (!drainErrors()) {
|
||||||
|
layerProvokingVertex = NormalizeProvokingVertexConvention(driverLayerConvention);
|
||||||
|
}
|
||||||
|
}
|
||||||
// GL_MAX_VIEWPORTS (0x825B), GL_VIEWPORT_SUBPIXEL_BITS (0x825C) and GL_VIEWPORT_BOUNDS_RANGE
|
// GL_MAX_VIEWPORTS (0x825B), GL_VIEWPORT_SUBPIXEL_BITS (0x825C) and GL_VIEWPORT_BOUNDS_RANGE
|
||||||
// (0x825D) all arrive with GL_OES_viewport_array and exist nowhere in ES core, so on the
|
// (0x825D) all arrive with GL_OES_viewport_array and exist nowhere in ES core, so on the
|
||||||
// drivers DirectGLES actually runs on all three raise GL_INVALID_ENUM. The values MobileGL
|
// drivers DirectGLES actually runs on all three raise GL_INVALID_ENUM. The values MobileGL
|
||||||
@@ -1272,9 +1321,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
// hold), floors GL_SUBPIXEL_BITS at its own 4, and the bounds range is clamped to the core
|
// hold), floors GL_SUBPIXEL_BITS at its own 4, and the bounds range is clamped to the core
|
||||||
// minimum below. What changes is that the errors stop being manufactured.
|
// minimum below. What changes is that the errors stop being manufactured.
|
||||||
if (caps.SupportsViewportArray) {
|
if (caps.SupportsViewportArray) {
|
||||||
|
GLint driverViewportIndexConvention = static_cast<GLint>(GL_UNDEFINED_VERTEX);
|
||||||
drainErrors();
|
drainErrors();
|
||||||
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORTS, &maxViewports);
|
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORTS, &maxViewports);
|
||||||
glesFuncs.glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &viewportSubpixelBits);
|
glesFuncs.glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &viewportSubpixelBits);
|
||||||
|
glesFuncs.glGetIntegerv(GL_VIEWPORT_INDEX_PROVOKING_VERTEX, &driverViewportIndexConvention);
|
||||||
if (glesFuncs.glGetFloatv) {
|
if (glesFuncs.glGetFloatv) {
|
||||||
glesFuncs.glGetFloatv(GL_VIEWPORT_BOUNDS_RANGE, viewportBoundsRange);
|
glesFuncs.glGetFloatv(GL_VIEWPORT_BOUNDS_RANGE, viewportBoundsRange);
|
||||||
}
|
}
|
||||||
@@ -1285,6 +1336,9 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
viewportSubpixelBits = 0;
|
viewportSubpixelBits = 0;
|
||||||
viewportBoundsRange[0] = -32768.0f;
|
viewportBoundsRange[0] = -32768.0f;
|
||||||
viewportBoundsRange[1] = 32767.0f;
|
viewportBoundsRange[1] = 32767.0f;
|
||||||
|
} else {
|
||||||
|
viewportIndexProvokingVertex =
|
||||||
|
NormalizeProvokingVertexConvention(driverViewportIndexConvention);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (caps.SupportsShaderMultisampleInterpolation && glesFuncs.glGetFloatv) {
|
if (caps.SupportsShaderMultisampleInterpolation && glesFuncs.glGetFloatv) {
|
||||||
@@ -1452,6 +1506,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
// extension the probe above never ran at all - so the flag, not the local, decides.
|
// extension the probe above never ran at all - so the flag, not the local, decides.
|
||||||
caps.MaxClipDistances = caps.SupportsClipDistance ? std::max(maxClipDistances, 0) : 0;
|
caps.MaxClipDistances = caps.SupportsClipDistance ? std::max(maxClipDistances, 0) : 0;
|
||||||
caps.MaxViewports = maxViewports;
|
caps.MaxViewports = maxViewports;
|
||||||
|
caps.LayerProvokingVertex = layerProvokingVertex;
|
||||||
|
caps.ViewportIndexProvokingVertex = viewportIndexProvokingVertex;
|
||||||
caps.MaxViewportWidth = maxViewportDims[0];
|
caps.MaxViewportWidth = maxViewportDims[0];
|
||||||
caps.MaxViewportHeight = maxViewportDims[1];
|
caps.MaxViewportHeight = maxViewportDims[1];
|
||||||
// Only ever WIDER than the core minimum: a driver that answered the query is allowed to
|
// Only ever WIDER than the core minimum: a driver that answered the query is allowed to
|
||||||
@@ -1543,6 +1599,9 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
MGLOG_I(" GL_VIEWPORT_BOUNDS_RANGE: [%.3f, %.3f]", caps.ViewportBoundsRangeMin,
|
MGLOG_I(" GL_VIEWPORT_BOUNDS_RANGE: [%.3f, %.3f]", caps.ViewportBoundsRangeMin,
|
||||||
caps.ViewportBoundsRangeMax);
|
caps.ViewportBoundsRangeMax);
|
||||||
MGLOG_I(" GL_VIEWPORT_SUBPIXEL_BITS: %d", caps.ViewportSubpixelBits);
|
MGLOG_I(" GL_VIEWPORT_SUBPIXEL_BITS: %d", caps.ViewportSubpixelBits);
|
||||||
|
MGLOG_I(" GL_LAYER_PROVOKING_VERTEX: %s", ProvokingVertexConventionName(caps.LayerProvokingVertex));
|
||||||
|
MGLOG_I(" GL_VIEWPORT_INDEX_PROVOKING_VERTEX: %s",
|
||||||
|
ProvokingVertexConventionName(caps.ViewportIndexProvokingVertex));
|
||||||
|
|
||||||
caps.IndirectDrawInstanceIdIncludesBaseInstance =
|
caps.IndirectDrawInstanceIdIncludesBaseInstance =
|
||||||
ProbeIndirectInstanceIdIncludesBaseInstance(caps, glesFuncs);
|
ProbeIndirectInstanceIdIncludesBaseInstance(caps, glesFuncs);
|
||||||
|
|||||||
@@ -1280,6 +1280,11 @@ namespace MobileGL {
|
|||||||
// in FillInGLESCapabilities.
|
// in FillInGLESCapabilities.
|
||||||
Int MaxClipDistances = 0;
|
Int MaxClipDistances = 0;
|
||||||
Int MaxViewports = 16;
|
Int MaxViewports = 16;
|
||||||
|
// GL_LAYER_PROVOKING_VERTEX (ES 3.2 core) and GL_VIEWPORT_INDEX_PROVOKING_VERTEX
|
||||||
|
// (GL_OES_viewport_array). GL_UNDEFINED_VERTEX is a legal answer for both and is what
|
||||||
|
// a driver that has neither is honestly saying.
|
||||||
|
GLenum LayerProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
|
GLenum ViewportIndexProvokingVertex = GL_UNDEFINED_VERTEX;
|
||||||
Int MaxViewportWidth = 16384;
|
Int MaxViewportWidth = 16384;
|
||||||
Int MaxViewportHeight = 16384;
|
Int MaxViewportHeight = 16384;
|
||||||
Float ViewportBoundsRangeMin = 0.0f;
|
Float ViewportBoundsRangeMin = 0.0f;
|
||||||
|
|||||||
Reference in New Issue
Block a user