mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Create 6 / Flywheel 1.0.6 now renders correctly with both flywheel:instancing and flywheel:indirect on DirectGLES and DirectVulkan (verified in-game on Adreno 830: waterwheels and cogwheels solid, animated, correct pairing, no crashes across all four combinations). - MG_State/MG_Impl: sync explicitly-ranged SSBO bindings of FLUSH_EXPLICIT persistent maps to the backend before compute dispatches. Flywheel writes its scatter-copy descriptors into the staging ring's persistent map and never flushes that span (UB per spec, works on drivers whose maps alias GPU-visible memory); our maps alias the CPU shadow, so the descriptors never reached the GPU: the scatter compute copied nothing (GLES: empty draw commands) or stale garbage (Vulkan: wild indirect commands ending in VK_ERROR_DEVICE_LOST). - MG_Impl/MG_Backend: real glFenceSync objects backed by backend fences (GLES: native ES syncs guarded by context generation and owner thread; Vulkan: buffer-manager frame serials), replacing always-signaled stubs that let Flywheel reclaim staging memory the GPU still reads. - MG_Backend/DirectGLES: compute dispatches now run the same per-program resource sync as draws (uniform-block bindings and sampler units must be re-established through the API because layout(binding) is stripped from transpiled ESSL) and rebind texture units afterwards; the cull shader used to read a stale _FlwFrameUniforms binding and the depth-pyramid downsample sampled a stale unit-0 texture, zeroing the Hi-Z pyramid and occlusion-culling all Flywheel geometry. Image uniforms are excluded from glUniform1i (ES bakes their unit via layout(binding)); image-unit sync is clamped to the device limit; eliminated/SSBO-classified uniform blocks are skipped. - MG_Backend/DirectGLES: gl_BaseInstance in native indirect draws reads the GPU-written command buffer through an injected mg_IndirectParams SSBO view addressed per draw instead of the zero CPU shadow; layout(binding) is preserved for SSBO/image declarations (ES has no API rebinding for them); the ES context ownership claim moved to a global atomic owner thread with an EGL ground-truth check, and deferred buffer op state is mutex-guarded, so ops cannot silently no-op after context migration. - MG_Backend/DirectVulkan: new RebaseInstanceIndexPass rewrites vertex InstanceIndex loads to (InstanceIndex - BaseInstance). glslang's relaxed Vulkan mode aliases gl_InstanceID to InstanceIndex, which includes firstInstance, but GL's gl_InstanceID is zero-based - draws with nonzero baseInstance paired meshes with wrong instance data (cogwheel drawn as a waterwheel, another wheel collapsed invisible). Gated on the shaderDrawParameters device feature. Sampled-read barriers additionally cover the compute stage (the Hi-Z downsample samples the depth attachment from compute), and short uniform-buffer ranges keep the existing zero-padding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
454 lines
22 KiB
C++
454 lines
22 KiB
C++
// MobileGL - MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#include "GL_Drawing.h"
|
|
#include <Config.h>
|
|
#include <MG_State/GLState/Core.h>
|
|
#include <MG_State/EGLState/Core.h>
|
|
#include <MG_Backend/BackendObjects.h>
|
|
|
|
namespace MobileGL::MG_Impl::GLImpl {
|
|
static Bool ValidateCurrentProgramForExecution(const char* functionName) {
|
|
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
|
if (!currentProgram) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "There is no current program object."));
|
|
return false;
|
|
}
|
|
|
|
if (!currentProgram->GetLinkStatus()) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
|
"The current program object is not linked."));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static Bool ValidateCurrentProgramForCompute(const char* functionName) {
|
|
if (!ValidateCurrentProgramForExecution(functionName)) return false;
|
|
|
|
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
|
|
if (currentProgram->GetShaderIndexByStage(ShaderStage::Compute) < 0) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
|
"The current program object has no compute shader stage."));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static Bool ValidatePrimitiveModeForBackend(const char* functionName, GLenum mode) {
|
|
const auto& activeBackendObject = MG_Backend::pActiveBackendObject;
|
|
if (!activeBackendObject) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName, "No active backend object."));
|
|
return false;
|
|
}
|
|
|
|
if (activeBackendObject->GetBackendType() == BackendType::DirectVulkan && mode == GL_LINE_LOOP) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>(
|
|
"MG_Impl/GLImpl", functionName,
|
|
"Primitive mode GL_LINE_LOOP is not supported by the DirectVulkan backend."));
|
|
return false;
|
|
}
|
|
|
|
const auto& vao = MG_State::pGLContext->GetBoundVertexArray();
|
|
if (MG_State::pEGLContext->IsCurrentContextOpenGLCoreProfile() && vao && vao->GetExternalIndex() == 0) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", functionName,
|
|
"Default vertex array object cannot be used for drawing in core profile."));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Clear_Backend(GLbitfield mask) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.Clear(mask);
|
|
}
|
|
|
|
void DrawElements_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElements(mode, count, type, indices);
|
|
}
|
|
|
|
void MultiDrawElements_Backend(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
|
GLsizei drawcount) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElements(mode, count, type, indices, drawcount);
|
|
}
|
|
|
|
void MultiDrawElementsBaseVertex_Backend(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
|
GLsizei drawcount, const GLint* basevertex) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount,
|
|
basevertex);
|
|
}
|
|
|
|
void DrawArrays_Backend(GLenum mode, GLint first, GLsizei count) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawArrays(mode, first, count);
|
|
}
|
|
|
|
void DrawElementsBaseVertex_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLint basevertex) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsBaseVertex(mode, count, type, indices, basevertex);
|
|
}
|
|
|
|
void MultiDrawElementsIndirect_Backend(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
|
|
GLsizei stride) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
|
}
|
|
|
|
void MultiDrawArraysIndirect_Backend(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
|
|
}
|
|
|
|
void MultiDrawElementsIndirectCount_Backend(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount(mode, type, indirect, drawcount,
|
|
maxdrawcount, stride);
|
|
}
|
|
|
|
void MultiDrawArraysIndirectCount_Backend(GLenum mode, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount,
|
|
stride);
|
|
}
|
|
|
|
void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
|
const void* indices, GLint basevertex) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawRangeElementsBaseVertex(mode, start, end, count, type, indices,
|
|
basevertex);
|
|
}
|
|
|
|
void DrawRangeElements_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
|
const void* indices) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawRangeElements(mode, start, end, count, type, indices);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseVertexBaseInstance_Backend(GLenum mode, GLsizei count, GLenum type,
|
|
const void* indices, GLsizei instancecount,
|
|
GLint basevertex, GLuint baseinstance) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsInstancedBaseVertexBaseInstance(
|
|
mode, count, type, indices, instancecount, basevertex, baseinstance);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseVertex_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLint basevertex) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount,
|
|
basevertex);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseInstance_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLuint baseinstance) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsInstancedBaseInstance(mode, count, type, indices,
|
|
instancecount, baseinstance);
|
|
}
|
|
|
|
void DrawElementsInstanced_Backend(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsInstanced(mode, count, type, indices, instancecount);
|
|
}
|
|
|
|
void DrawElementsIndirect_Backend(GLenum mode, GLenum type, const void* indirect) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawElementsIndirect(mode, type, indirect);
|
|
}
|
|
void DrawArraysInstancedBaseInstance_Backend(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
|
GLuint baseinstance) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawArraysInstancedBaseInstance(mode, first, count, instancecount,
|
|
baseinstance);
|
|
}
|
|
|
|
void DrawArraysInstanced_Backend(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawArraysInstanced(mode, first, count, instancecount);
|
|
}
|
|
|
|
void DrawArraysIndirect_Backend(GLenum mode, const void* indirect) {
|
|
#ifdef TRACY_ENABLE
|
|
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
|
#endif
|
|
MG_Backend::gBackendFunctionsTable.GL.DrawArraysIndirect(mode, indirect);
|
|
}
|
|
|
|
// Flywheel-style engines write GPU-copy descriptors into a FLUSH_EXPLICIT
|
|
// persistent map and glBindBufferRange that span as an SSBO for a compute
|
|
// dispatch WITHOUT ever flushing it (undefined per spec, but real drivers'
|
|
// persistent maps alias GPU-visible memory, so it works there). MobileGL's
|
|
// persistent maps alias the CPU shadow, so those bytes would never reach the
|
|
// GPU: push every explicitly-ranged SSBO binding of such maps down right
|
|
// before each dispatch. Whole-buffer (BindBufferBase) bindings are excluded
|
|
// on purpose — ranges the app DID flush already arrived, and re-uploading a
|
|
// 16MB staging ring per dispatch would be prohibitive.
|
|
static void SyncUnflushedMappedSsboRangesForDispatch() {
|
|
const auto pointCount = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage);
|
|
for (SizeT i = 0; i < pointCount; ++i) {
|
|
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, i);
|
|
if (!point.HasExplicitRange()) continue;
|
|
const auto& bufferObject = point.GetBoundObject();
|
|
if (!bufferObject) continue;
|
|
bufferObject->SyncMappedRangeForGpuRead(point.GetRange());
|
|
}
|
|
}
|
|
|
|
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
|
|
auto dispatchCompute = MG_Backend::gBackendFunctionsTable.GL.DispatchCompute;
|
|
if (!dispatchCompute) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support compute dispatch."));
|
|
return;
|
|
}
|
|
if (!ValidateCurrentProgramForCompute(__func__)) return;
|
|
SyncUnflushedMappedSsboRangesForDispatch();
|
|
dispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
|
|
}
|
|
|
|
void DispatchComputeIndirect(GLintptr indirect) {
|
|
auto dispatchComputeIndirect = MG_Backend::gBackendFunctionsTable.GL.DispatchComputeIndirect;
|
|
if (!dispatchComputeIndirect) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
|
"Backend does not support indirect compute dispatch."));
|
|
return;
|
|
}
|
|
if (!ValidateCurrentProgramForCompute(__func__)) return;
|
|
SyncUnflushedMappedSsboRangesForDispatch();
|
|
dispatchComputeIndirect(indirect);
|
|
}
|
|
|
|
void MemoryBarrier(GLbitfield barriers) {
|
|
auto memoryBarrier = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrier;
|
|
if (!memoryBarrier) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Backend does not support memory barriers."));
|
|
return;
|
|
}
|
|
memoryBarrier(barriers);
|
|
}
|
|
|
|
void MemoryBarrierByRegion(GLbitfield barriers) {
|
|
auto memoryBarrierByRegion = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrierByRegion;
|
|
if (!memoryBarrierByRegion) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
|
"Backend does not support regional memory barriers."));
|
|
return;
|
|
}
|
|
memoryBarrierByRegion(barriers);
|
|
}
|
|
|
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
MultiDrawElementsIndirect_Backend(mode, type, indirect, drawcount, stride);
|
|
}
|
|
|
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
|
|
}
|
|
|
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride) {
|
|
auto multiDrawElementsIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount;
|
|
if (!multiDrawElementsIndirectCount) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
|
"Backend does not support indirect-parameter indexed draws."));
|
|
return;
|
|
}
|
|
MultiDrawElementsIndirectCount_Backend(mode, type, indirect, drawcount, maxdrawcount, stride);
|
|
}
|
|
|
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride) {
|
|
auto multiDrawArraysIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount;
|
|
if (!multiDrawArraysIndirectCount) {
|
|
MG_State::pGLContext->RecordError(
|
|
ErrorCode::InvalidOperation,
|
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
|
"Backend does not support indirect-parameter array draws."));
|
|
return;
|
|
}
|
|
MultiDrawArraysIndirectCount_Backend(mode, indirect, drawcount, maxdrawcount, stride);
|
|
}
|
|
|
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
|
const void* indices, GLint basevertex) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawRangeElementsBaseVertex_Backend(mode, start, end, count, type, indices, basevertex);
|
|
}
|
|
|
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawRangeElements_Backend(mode, start, end, count, type, indices);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLint basevertex, GLuint baseinstance) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsInstancedBaseVertexBaseInstance_Backend(mode, count, type, indices, instancecount, basevertex,
|
|
baseinstance);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLint basevertex) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsInstancedBaseVertex_Backend(mode, count, type, indices, instancecount, basevertex);
|
|
}
|
|
|
|
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLuint baseinstance) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsInstancedBaseInstance_Backend(mode, count, type, indices, instancecount, baseinstance);
|
|
}
|
|
|
|
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsInstanced_Backend(mode, count, type, indices, instancecount);
|
|
}
|
|
|
|
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsIndirect_Backend(mode, type, indirect);
|
|
}
|
|
|
|
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
|
GLuint baseinstance) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawArraysInstancedBaseInstance_Backend(mode, first, count, instancecount, baseinstance);
|
|
}
|
|
|
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawArraysInstanced_Backend(mode, first, count, instancecount);
|
|
}
|
|
|
|
void DrawArraysIndirect(GLenum mode, const void* indirect) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawArraysIndirect_Backend(mode, indirect);
|
|
}
|
|
|
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElementsBaseVertex_Backend(mode, count, type, indices, basevertex);
|
|
}
|
|
|
|
void DrawArrays(GLenum mode, GLint first, GLsizei count) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawArrays_Backend(mode, first, count);
|
|
}
|
|
|
|
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
|
GLsizei drawcount) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
MultiDrawElements_Backend(mode, count, type, indices, drawcount);
|
|
}
|
|
|
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices,
|
|
GLsizei drawcount, const GLint* basevertex) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
MultiDrawElementsBaseVertex_Backend(mode, count, type, indices, drawcount, basevertex);
|
|
}
|
|
|
|
void Clear(GLbitfield mask) {
|
|
Clear_Backend(mask);
|
|
}
|
|
|
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
|
|
if (!ValidateCurrentProgramForExecution(__func__)) return;
|
|
if (!ValidatePrimitiveModeForBackend(__func__, mode)) return;
|
|
DrawElements_Backend(mode, count, type, indices);
|
|
}
|
|
|
|
} // namespace MobileGL::MG_Impl::GLImpl
|