mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-10 13:18:31 +09:00
[Feat] (MG_Backend): wire primitive restart into both backends; detect dualSrcBlend
Make GL_PRIMITIVE_RESTART[_FIXED_INDEX] actually take effect at draw time, following the detect-at-init / POST / fallback-or-hard-fail discipline. DirectVulkan: - Thread primitiveRestartEnable through the pipeline (payload + hash + input-assembly), set from the GL_PRIMITIVE_RESTART / _FIXED_INDEX caps. - Detect and enable primitiveTopologyListRestart (VK_EXT_primitive_topology_list_restart) at device creation; cache it. Strip/fan restart needs no feature; a *list* topology with restart and no feature hard-fails at the draw with the reason. - Vulkan only restarts on the fixed all-ones index value, so an arbitrary GL_PRIMITIVE_RESTART index that is not that value hard-fails in UploadAndBindIndexBuffer (where the index type is known). - Also detect+enable and cache the dualSrcBlend base feature (groundwork for GL_SRC1_* dual-source blending). DirectGLES: - Sync GL_PRIMITIVE_RESTART_FIXED_INDEX from either restart cap (GLES core has only the fixed-index form); an arbitrary non-fixed index hard-fails in the indexed draw paths with the reason. POST: dualSrcBlend and primitiveTopologyListRestart capability rows (Pass when supported, Warn with the fallback/hard-fail consequence otherwise). Library builds clean; SanityTest 31/31. (The actual restart rendering and the hard-fail paths need a real GPU and are not runtime-testable here.)
This commit is contained in:
@@ -564,6 +564,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
#undef SYNC_CAPABILITY
|
||||
|
||||
{ // Primitive restart. GLES core has only GL_PRIMITIVE_RESTART_FIXED_INDEX (fixed all-ones
|
||||
// value); both the fixed cap and the (fixed-valued) arbitrary GL_PRIMITIVE_RESTART map to
|
||||
// it. An arbitrary non-fixed restart index is rejected at draw time (see DrawElements).
|
||||
const Bool restart = parameters.PrimitiveRestartFixedIndexEnabled || parameters.PrimitiveRestartEnabled;
|
||||
const Bool syncedRestart = g_syncedRenderStateParameters.PrimitiveRestartFixedIndexEnabled ||
|
||||
g_syncedRenderStateParameters.PrimitiveRestartEnabled;
|
||||
if (restart != syncedRestart) {
|
||||
restart ? g_GLESFuncs.glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX)
|
||||
: g_GLESFuncs.glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
}
|
||||
}
|
||||
|
||||
const auto& ToGLBoolean = [](Bool b) -> GLboolean { return b ? GL_TRUE : GL_FALSE; };
|
||||
|
||||
{ // Blend State
|
||||
@@ -1329,12 +1341,38 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_GLESFuncs.glClear(mask);
|
||||
}
|
||||
|
||||
// GLES core supports only GL_PRIMITIVE_RESTART_FIXED_INDEX (fixed all-ones value). If the app
|
||||
// enabled the arbitrary GL_PRIMITIVE_RESTART with a non-fixed index, hard-fail at this draw with
|
||||
// the reason (a fallback would silently drop restarts and corrupt geometry).
|
||||
void CheckPrimitiveRestartSupported(GLenum indexType) {
|
||||
if (!MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) ||
|
||||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex)) {
|
||||
return;
|
||||
}
|
||||
Uint32 fixedMax = 0;
|
||||
switch (indexType) {
|
||||
case GL_UNSIGNED_BYTE: fixedMax = 0xFFu; break;
|
||||
case GL_UNSIGNED_SHORT: fixedMax = 0xFFFFu; break;
|
||||
case GL_UNSIGNED_INT: fixedMax = 0xFFFFFFFFu; break;
|
||||
default: return;
|
||||
}
|
||||
const Uint32 restartIndex = MG_State::pGLContext->GetPrimitiveRestartIndex();
|
||||
if (restartIndex != fixedMax) {
|
||||
THROW_EXCEPTION("GL_PRIMITIVE_RESTART with an arbitrary restart index (" + std::to_string(restartIndex) +
|
||||
") is not supported by the GLES backend, which only restarts on the fixed index value (" +
|
||||
std::to_string(fixedMax) +
|
||||
") for this index type; use GL_PRIMITIVE_RESTART_FIXED_INDEX or set glPrimitiveRestartIndex "
|
||||
"to that value.");
|
||||
}
|
||||
}
|
||||
|
||||
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
||||
DebugImpl::OpenGLScopeMarker marker(__func__);
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer;
|
||||
PrepareForDraw(syncBit);
|
||||
CheckPrimitiveRestartSupported(type);
|
||||
g_GLESFuncs.glDrawElements(mode, count, type, indices);
|
||||
}
|
||||
|
||||
@@ -1360,6 +1398,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer;
|
||||
PrepareForDraw(syncBit);
|
||||
CheckPrimitiveRestartSupported(type);
|
||||
g_GLESFuncs.glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
|
||||
}
|
||||
|
||||
@@ -1390,6 +1429,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer;
|
||||
PrepareForDraw(syncBit);
|
||||
CheckPrimitiveRestartSupported(type);
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
g_GLESFuncs.glDrawElements(mode, count[i], type, indices[i]);
|
||||
@@ -1403,6 +1443,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer;
|
||||
PrepareForDraw(syncBit);
|
||||
CheckPrimitiveRestartSupported(type);
|
||||
|
||||
for (GLsizei i = 0; i < drawcount; ++i) {
|
||||
g_GLESFuncs.glDrawElementsBaseVertex(mode, count[i], type, indices[i], basevertex[i]);
|
||||
|
||||
Reference in New Issue
Block a user