mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
Wave 2 of the advertised-extension conformance campaign.
PROGRAM INTERFACE QUERIES (the load-bearing piece). glGetProgramInterfaceiv
and the five glGetProgramResource* entry points were answered by the
BACKENDS - Espryt asked the real driver about SPIRV-Cross-generated ESSL
whose namespace is not the GL one (default-block uniforms live in
MGL_GLOBAL_UBO there), and Magma kept a second, partial reflection that
hardcoded types and diverged from the frontend. Both are now deleted; a new
frontend resource-model layer (ProgramInterface.{h,cpp}) answers every
interface - uniforms, uniform blocks, atomic-counter buffers (recovered
from glslang's synthesized gl_AtomicCounterBlock_<binding> lowering),
buffer variables, shader-storage blocks (classified by TType storage
qualifier since glslang reflects them as uniform blocks), program inputs/
outputs (built-ins' layoutLocationEnd sentinel mapped to -1), and
transform-feedback varyings including the gl_NextBuffer/gl_SkipComponentsN
pseudo-varyings - from the glslang reflection the frontend already trusts
for glGetActiveUniform. Name/index round-tripping, the "[0]" array
spelling, and the GL 4.6 table 7.2 prop/error matrix live in the new layer
only; GetActiveUniform*/GetActiveAttrib* are untouched.
glShaderStorageBlockBinding now takes the interface-layer index (the one
GetProgramResourceIndex returns, with a range check it never had), records
the binding on the program keyed by block NAME - the one coordinate all
three index spaces agree on - and delegates by name across the backend
boundary. Both backends reseed the recorded bindings on their own program
rebuilds, so an unrelated resync can no longer silently revert a rebound
block, and GL_BUFFER_BINDING reports the live binding, not the declared
one. The Espryt delegate applies only to an already-synced twin and can no
longer trigger SyncToBackend from a getter; the sync path's GL query
out-params are initialized and clamped (a load-dependent stack-garbage
Vector size crash caught by the gate, reproduced 3/50 pre-fix, 100/100
post-fix under saturating load).
ESPRYT RENDER-STATE SHADOW RESET (rides along because it shares
DirectGLES.cpp): the render-state shadow is file-static and survives
MobileGL context switches, so GL_FRAMEBUFFER_SRGB (and the whole synced-cap
class) leaked between contexts - the cross-test leakage class the CTS maps
have carried for a week. MakeCurrent now invalidates the shadow like it
already invalidates the program/FBO/buffer caches, and the resync resolves
a never-set scissor box to the current surface instead of pushing the
(0,0,0,0) sentinel verbatim (which scissored everything away - caught by
the retrace gate, bisected to the exact field via a bitmask probe, and
fixed by resolving like the viewport path rather than reverting).
Frontend riders exposed by the layer: glGetUniformLocation resolves
arrays-of-arrays element addressing ("a[2][1]"); transform-feedback capture
accepts element-addressed varying names ("b[1]") and snapshots the request
verbatim for the interface (Magma's decorate pass logs loudly that element
capture is unimplemented there - follow-up).
KNOWN GAPS, documented in code and tests: the 6 subroutines-* cases
(glslang refuses subroutine for SPIR-V; wave 3), the 5 separate-programs-*
cases (glslang's pipe-I/O reflection cannot see a separable non-vertex
stage's own inputs; needs stage-aware output validation first), and
uniform-block-types' per-instance stage masks (not derivable from the
reflection).
Gate: 593/593 unit at default and kill-switch, x10 each, plus the SSB race
case 100/100 under 20-way CPU load; ext caselist Espryt 77.87% -> 80.42%,
Magma 77.58% -> 79.39% (+212 fixed, 0 newly broken); program_interface_query
2/43 -> 31/43 unique on Espryt, 9/43 -> 31/43 on Magma, backends now
byte-identical; KHR-GL45.direct_state_access 370/371 + 371/371 with the 4
sRGB leak victims recovered in cross-test ordering; KHR-GL33 held at
9884/9886; full 39x2 CI retrace with zero wave-attributable failures (the
3 failing newly-added fixtures are bit-identical on the pristine baseline).
141 lines
9.8 KiB
C++
141 lines
9.8 KiB
C++
// MobileGL - MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h
|
|
// 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
|
|
|
|
#pragma once
|
|
#include <Includes.h>
|
|
#include <MG_Backend/BackendObject.h>
|
|
#include "Renderer/VulkanRenderer.h"
|
|
|
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
|
extern UniquePtr<VulkanRenderer>& pVulkanRenderer;
|
|
|
|
// Generation of the live VulkanRenderer instance, mirroring DirectGLES's
|
|
// g_syncContextGeneration. BackendObject_DirectVulkan bumps it wherever
|
|
// pVulkanRenderer is reset or recreated; fence and timer-query handles
|
|
// stamped with an older generation are stale and resolve as signaled /
|
|
// available with zero results instead of dereferencing the destroyed
|
|
// renderer's frame serials and query-pool slots.
|
|
Uint64 GetRendererGeneration();
|
|
void BumpRendererGeneration();
|
|
|
|
// Drops every cached program-resource reflection entry (CPU-side strings/vectors
|
|
// only, no Vulkan handles). Called at EGL teardown next to the renderer reset;
|
|
// safe because GL calls are serialized in this codebase, and any still-live
|
|
// program rebuilds its entry from the retained generated SPIR-V on demand.
|
|
void ClearProgramResourceCaches();
|
|
|
|
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
|
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
|
|
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
|
|
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
|
|
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
|
GLint drawbuffer, const GLfloat* value);
|
|
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
|
GLint drawbuffer, const GLint* value);
|
|
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
|
GLint drawbuffer, const GLuint* value);
|
|
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
|
|
GLint drawbuffer, GLfloat depth, GLint stencil);
|
|
void Clear(GLbitfield mask);
|
|
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
|
void DrawArrays(GLenum mode, GLint first, GLsizei count);
|
|
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex);
|
|
void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount);
|
|
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
|
GLsizei drawcount);
|
|
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
|
|
GLsizei drawcount, const GLint* basevertex);
|
|
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride);
|
|
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
|
|
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride);
|
|
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
|
|
GLsizei maxdrawcount, GLsizei stride);
|
|
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
|
|
const void* indices, GLint basevertex);
|
|
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
|
|
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLint basevertex, GLuint baseinstance);
|
|
void DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLint basevertex);
|
|
void DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
|
|
GLsizei instancecount, GLuint baseinstance);
|
|
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount);
|
|
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect);
|
|
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
|
GLuint baseinstance);
|
|
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
|
void DrawArraysIndirect(GLenum mode, const void* indirect);
|
|
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
|
|
GLint dstY1, GLbitfield mask, GLenum filter);
|
|
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
|
|
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
|
|
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
|
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
|
|
GLbitfield mask, GLenum filter);
|
|
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
|
GLsizei height, GLint border);
|
|
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
|
GLsizei height);
|
|
void CopyImageSubData(const SharedPtr<MG_State::GLState::ITextureObject>& srcTexture,
|
|
GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ,
|
|
const SharedPtr<MG_State::GLState::ITextureObject>& dstTexture,
|
|
GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ,
|
|
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
|
|
void GenerateMipmap(GLenum target);
|
|
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
|
|
void DispatchComputeIndirect(GLintptr indirect);
|
|
void MemoryBarrier(GLbitfield barriers);
|
|
void MemoryBarrierByRegion(GLbitfield barriers);
|
|
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
|
|
GLenum format);
|
|
void GetIntegeri_v(GLenum target, GLuint index, GLint* data);
|
|
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
|
|
void GetProgramiv(GLuint program, GLenum pname, GLint* params);
|
|
void ShaderStorageBlockBinding(GLuint program, const GLchar* storageBlockName, GLuint storageBlockBinding);
|
|
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
|
|
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
|
|
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
|
|
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels);
|
|
// GL fence sync objects, mapped onto the renderer's frame-serial busy
|
|
// tracking: a fence captures the frame serial current at creation and is
|
|
// signaled once every command recorded under that serial has completed on
|
|
// the GPU.
|
|
BackendSyncHandle FenceSync();
|
|
GLenum ClientWaitSync(BackendSyncHandle sync, GLbitfield flags, GLuint64 timeout);
|
|
void WaitSync(BackendSyncHandle sync, GLbitfield flags, GLuint64 timeout);
|
|
void DeleteSync(BackendSyncHandle sync);
|
|
Bool GetSyncStatus(BackendSyncHandle sync);
|
|
// GPU timer queries (GL_TIME_ELAPSED spans and GL_TIMESTAMP one-shots),
|
|
// backed by per-frame VkQueryPool timestamp slots. All hooks degrade
|
|
// gracefully: null handles when the renderer is absent, the device lacks
|
|
// timestamp support, or the frame's pool is exhausted.
|
|
// Dynamic support check (GLFunctionsTable::IsTimerQuerySupported): true
|
|
// only while a live renderer exists whose device can actually time.
|
|
Bool IsTimerQuerySupported();
|
|
BackendQueryHandle BeginTimeElapsedQuery();
|
|
BackendQueryHandle BeginXfbPrimitivesQuery(Bool generated);
|
|
void EndXfbPrimitivesQuery(BackendQueryHandle query);
|
|
BackendQueryHandle BeginOcclusionQuery();
|
|
void EndOcclusionQuery(BackendQueryHandle query);
|
|
void EndTimeElapsedQuery(BackendQueryHandle query);
|
|
BackendQueryHandle QueryCounterTimestamp();
|
|
Bool IsQueryResultAvailable(BackendQueryHandle query);
|
|
// Returns true when a final value was produced (outNanoseconds set; the
|
|
// frontend may cache it and release the handle), false when the result
|
|
// cannot be obtained yet (e.g. a wait refused because the records' frame
|
|
// serial is the current unsubmitted frame) - the handle then stays
|
|
// readable later.
|
|
Bool GetQueryResult64(BackendQueryHandle query, Bool wait, Uint64* outNanoseconds);
|
|
void DeleteBackendQuery(BackendQueryHandle query);
|
|
// Always 0: Vulkan cannot synchronously sample the GPU clock (timestamps
|
|
// only exist as vkCmdWriteTimestamp results); the frontend falls back.
|
|
Int64 GetGpuTimestampNs();
|
|
void Present();
|
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|