mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Refactor] (CMakeLists.txt, MG_Backend, MG_Backend/DirectVulkan, MG_Impl/GLImpl, MG_Impl/Pipe, MG_IntegrationTest/Scenarios, MG_Pipe/generated, MG_Remote/Client, MG_Test/Query, MG_Test/Texture, scripts, scripts/data): move the function table and shared-image types out of BackendObject.h
- BackendFunctions.h holds GLFunctionsTable, GlobalBackendFunctionsTable, CopyImageEndpoint, the sync and query handles and the present damage; files that only call through the table include it instead of the backend object - SharedImageTypes.h holds the shared-image structs - FormatCapabilities.cpp holds the BackendCaps.h helpers that BackendObject.cpp defined - gen_pipe.py reads the table from its new header - two comments that cited a BackendObject.cpp line name the function instead
This commit is contained in:
@@ -496,6 +496,8 @@ set(SOURCE_FILES
|
|||||||
|
|
||||||
MobileGL/MG_Backend/Init.cpp
|
MobileGL/MG_Backend/Init.cpp
|
||||||
MobileGL/MG_Backend/BackendObject.cpp
|
MobileGL/MG_Backend/BackendObject.cpp
|
||||||
|
MobileGL/MG_Backend/BackendFunctions.cpp
|
||||||
|
MobileGL/MG_Backend/FormatCapabilities.cpp
|
||||||
MobileGL/MG_Backend/ClientReadback.cpp
|
MobileGL/MG_Backend/ClientReadback.cpp
|
||||||
MobileGL/MG_Backend/GpuHangWatch.cpp
|
MobileGL/MG_Backend/GpuHangWatch.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/BackendFunctions.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 "BackendFunctions.h"
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend {
|
||||||
|
namespace {
|
||||||
|
MG_Util::Damage::Region& PresentDamageSlot() {
|
||||||
|
thread_local MG_Util::Damage::Region damage = MG_Util::Damage::Region::Full();
|
||||||
|
return damage;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const MG_Util::Damage::Region& CurrentPresentDamage() {
|
||||||
|
return PresentDamageSlot();
|
||||||
|
}
|
||||||
|
void SetCurrentPresentDamage(const MG_Util::Damage::Region& damage) {
|
||||||
|
PresentDamageSlot() = damage;
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/BackendFunctions.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_State/GLState/TextureState/TextureEnum.h"
|
||||||
|
#include <MG_Util/Damage/Damage.h>
|
||||||
|
#include <MG_Pipe/MGPipeHandles.h>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_State::GLState {
|
||||||
|
class FramebufferObject;
|
||||||
|
class ITextureObject;
|
||||||
|
class RenderbufferObject;
|
||||||
|
} // namespace MobileGL::MG_State::GLState
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend {
|
||||||
|
// One endpoint of a glCopyImageSubData. GL 4.6 core 18.3.2 accepts GL_RENDERBUFFER
|
||||||
|
// alongside the ten whole-image texture targets, and a renderbuffer name lives in a
|
||||||
|
// namespace of its own - so an endpoint is a sum type, not an ITextureObject. At most
|
||||||
|
// one of the two pointers is set; neither is set when the name named nothing, which is
|
||||||
|
// the INVALID_VALUE the frontend validator reports.
|
||||||
|
struct CopyImageEndpoint {
|
||||||
|
SharedPtr<MG_State::GLState::ITextureObject> Texture;
|
||||||
|
SharedPtr<MG_State::GLState::RenderbufferObject> Renderbuffer;
|
||||||
|
MG_Pipe::MGPipeHandle TextureHandle = MG_Pipe::kMGPipeNullHandle;
|
||||||
|
MG_Pipe::MGPipeHandle RenderbufferHandle = MG_Pipe::kMGPipeNullHandle;
|
||||||
|
|
||||||
|
Bool IsRenderbuffer() const {
|
||||||
|
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
||||||
|
return Renderbuffer != nullptr;
|
||||||
|
}
|
||||||
|
Bool Exists() const {
|
||||||
|
if (!MG_Pipe::MGPipeHandleIsNull(TextureHandle)) return true;
|
||||||
|
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
||||||
|
return Texture != nullptr || Renderbuffer != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Opaque backend fence-sync handle, created by GLFunctionsTable::FenceSync
|
||||||
|
// and released by GLFunctionsTable::DeleteSync.
|
||||||
|
using BackendSyncHandle = void*;
|
||||||
|
|
||||||
|
// Opaque backend timer-query handle, created by
|
||||||
|
// GLFunctionsTable::BeginTimeElapsedQuery / QueryCounterTimestamp and
|
||||||
|
// released by GLFunctionsTable::DeleteBackendQuery.
|
||||||
|
using BackendQueryHandle = void*;
|
||||||
|
|
||||||
|
struct GLFunctionsTable {
|
||||||
|
void (*DrawArrays)(GLenum mode, GLint first, GLsizei count);
|
||||||
|
void (*DrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
||||||
|
void (*DrawElementsBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void* 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 (*DrawArraysInstancedBaseInstance)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
||||||
|
GLuint baseinstance);
|
||||||
|
void (*DrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
||||||
|
void (*DrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect);
|
||||||
|
void (*DrawArraysIndirect)(GLenum mode, const void* indirect);
|
||||||
|
void (*Clear)(GLbitfield mask);
|
||||||
|
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 (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
|
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||||
|
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 (*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);
|
||||||
|
// The by-name form: the destination is `texture`, whatever the units hold. `target` is
|
||||||
|
// the one the record carries (the texture's own 2D-class target).
|
||||||
|
void (*CopyTextureSubImage2D)(const SharedPtr<MG_State::GLState::ITextureObject>& texture, GLenum target,
|
||||||
|
GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||||
|
GLsizei height);
|
||||||
|
void (*CopyImageSubData)(const CopyImageEndpoint& src, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY,
|
||||||
|
GLint srcZ, const CopyImageEndpoint& dst, GLenum dstTarget, GLint dstLevel, GLint dstX,
|
||||||
|
GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
|
||||||
|
void (*GenerateMipmap)(GLenum target);
|
||||||
|
// The by-name form, also used once the bound-target form has resolved its texture.
|
||||||
|
void (*GenerateTextureMipmap)(const SharedPtr<MG_State::GLState::ITextureObject>& texture, GLenum target);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
// The ONLY indexed query that is genuinely a backend one, and only for the pnames
|
||||||
|
// MG_Impl/GLImpl/Getter/GL_Getter.cpp does not already own. Every indexed pname that
|
||||||
|
// names FRONTEND state - the indexed buffer bindings, the per-unit texture/sampler
|
||||||
|
// bindings, the image-unit bindings, the viewport rectangles, the indexed capabilities
|
||||||
|
// - is answered in GL_Getter::GetIntegeri_v and never reaches this entry; the
|
||||||
|
// 64-bit and float/double widths are derived there from the same answer, which is why
|
||||||
|
// no GetInteger64i_v/GetFloati_v/GetDoublei_v table entry exists. In practice this
|
||||||
|
// leaves GL_MAX_COMPUTE_WORK_GROUP_COUNT / _SIZE (also asked directly by
|
||||||
|
// MG_Util/ShaderTranspiler/CompileEnv.cpp) plus whatever pname the frontend has no
|
||||||
|
// case for at all.
|
||||||
|
void (*GetIntegeri_v)(GLenum target, GLuint index, GLint* data);
|
||||||
|
// There is deliberately NO GetProgramiv entry: glGetProgramiv describes the program
|
||||||
|
// the APPLICATION wrote - link status, the transform-feedback mode, the compute local
|
||||||
|
// size - all of which are frontend link artifacts on ProgramObject, and
|
||||||
|
// MG_Impl/GLImpl/Program/GL_Program.cpp answers every one of them from there. Asking a
|
||||||
|
// backend would mean asking about a DIFFERENT program (a SPIRV-Cross-generated ESSL
|
||||||
|
// one, or a SPIR-V module), in a namespace the application never sees.
|
||||||
|
// The GL program interface (glGetProgramInterfaceiv / glGetProgramResource*) is NOT
|
||||||
|
// a backend query: it describes the program the application wrote, in the
|
||||||
|
// application's namespace, which neither backend program is in. It is answered
|
||||||
|
// entirely by MG_Impl/GLImpl/Program/ProgramInterface from the frontend reflection.
|
||||||
|
// Takes the block's GL NAME, not glShaderStorageBlockBinding's index. The index
|
||||||
|
// the application passes is the frontend interface-query enumeration's, and no
|
||||||
|
// backend shares that index space: DirectVulkan enumerates SPIR-V descriptor
|
||||||
|
// bindings and DirectGLES asks a real driver about SPIRV-Cross-generated ESSL.
|
||||||
|
// The name is the one coordinate all three agree on, so the frontend resolves the
|
||||||
|
// index against its own enumeration and each backend maps the name to its own.
|
||||||
|
void (*ShaderStorageBlockBinding)(GLuint program, const GLchar* storageBlockName, GLuint storageBlockBinding);
|
||||||
|
// GL fence sync objects. All entries are optional (may be null); the
|
||||||
|
// frontend then falls back to always-signaled sync semantics.
|
||||||
|
// FenceSync may itself return null when the backend cannot create a
|
||||||
|
// fence right now (e.g. the calling thread does not own the backend
|
||||||
|
// context); the frontend treats such a sync as always signaled.
|
||||||
|
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); // true = signaled
|
||||||
|
// GL timer-query objects (GL_ARB_timer_query). All entries are
|
||||||
|
// optional (may be null); the frontend then falls back to zero
|
||||||
|
// results and reports GL_QUERY_COUNTER_BITS == 0.
|
||||||
|
// BeginTimeElapsedQuery / QueryCounterTimestamp may themselves
|
||||||
|
// return null when the backend cannot create a query right now;
|
||||||
|
// the frontend treats such a query as immediately available with
|
||||||
|
// a zero result.
|
||||||
|
// Dynamic support check: true only when the live backend can
|
||||||
|
// actually time at the moment of the call (extension / entry
|
||||||
|
// points / timestamp valid bits are known then, not at table
|
||||||
|
// init). Gates the advertised GL_QUERY_COUNTER_BITS.
|
||||||
|
Bool (*IsTimerQuerySupported)();
|
||||||
|
BackendQueryHandle (*BeginTimeElapsedQuery)(); // starts a TIME_ELAPSED span
|
||||||
|
void (*EndTimeElapsedQuery)(BackendQueryHandle query); // ends the span
|
||||||
|
BackendQueryHandle (*QueryCounterTimestamp)(); // glQueryCounter(GL_TIMESTAMP) one-shot
|
||||||
|
Bool (*IsQueryResultAvailable)(BackendQueryHandle query); // non-blocking
|
||||||
|
// Returns true when a final value was produced (*outNanoseconds
|
||||||
|
// written; the frontend may cache it and release the handle).
|
||||||
|
// Returns false when the result could not be obtained YET - e.g.
|
||||||
|
// a Vulkan wait that refuses to block on a not-yet-submitted
|
||||||
|
// frame serial - in which case the frontend must keep the handle
|
||||||
|
// and leave the query readable later.
|
||||||
|
Bool (*GetQueryResult64)(BackendQueryHandle query, Bool wait, Uint64* outNanoseconds);
|
||||||
|
void (*DeleteBackendQuery)(BackendQueryHandle query);
|
||||||
|
// GL_SAMPLES_PASSED occlusion queries (optional; null = unsupported,
|
||||||
|
// the frontend then rejects the target). Results/deletion flow through
|
||||||
|
// GetQueryResult64 / DeleteBackendQuery like timer queries.
|
||||||
|
BackendQueryHandle (*BeginOcclusionQuery)();
|
||||||
|
void (*EndOcclusionQuery)(BackendQueryHandle query);
|
||||||
|
// Transform feedback primitive queries backed by real GPU query pools
|
||||||
|
// (optional; null = frontend falls back to CPU accounting).
|
||||||
|
BackendQueryHandle (*BeginXfbPrimitivesQuery)(Bool generated);
|
||||||
|
void (*EndXfbPrimitivesQuery)(BackendQueryHandle query);
|
||||||
|
// Whether GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN should be answered from the
|
||||||
|
// frontend's own accounting wherever that accounting is exact - a capture with no
|
||||||
|
// geometry stage - instead of from the query above. Set by DirectGLES, whose result
|
||||||
|
// is whatever the ES driver's PRIMITIVES_WRITTEN counter says: Adreno reports twice
|
||||||
|
// the written count for a vertex-only capture that follows a large render pass,
|
||||||
|
// where the desktop-exact answer is the one the frontend already computed. Defaults
|
||||||
|
// to false, so a backend that never sets it keeps using its GPU result.
|
||||||
|
Bool PrefersCpuXfbPrimitiveAccounting = false;
|
||||||
|
// Transform feedback capture spans, for backends whose own GL/ES driver
|
||||||
|
// performs the capture (DirectGLES). Both optional; null means the backend
|
||||||
|
// drives capture from its draw recording instead (DirectVulkan). End is
|
||||||
|
// called while the frontend capture state is still active, so the backend
|
||||||
|
// can still see the capture program and buffer bindings.
|
||||||
|
// GL_PATCH_VERTICES; ES 3.2 spells it the same way.
|
||||||
|
void (*PatchParameteri)(GLenum pname, GLint value);
|
||||||
|
void (*BeginTransformFeedback)(GLenum primitiveMode);
|
||||||
|
void (*EndTransformFeedback)();
|
||||||
|
// ARB_transform_feedback2. A backend that leaves these null keeps the single
|
||||||
|
// implicit capture span the frontend has always modelled; the frontend state
|
||||||
|
// (paused flag, per-object bindings) is tracked either way.
|
||||||
|
void (*PauseTransformFeedback)();
|
||||||
|
void (*ResumeTransformFeedback)();
|
||||||
|
void (*BindTransformFeedback)(GLuint name);
|
||||||
|
void (*DeleteTransformFeedback)(GLuint name);
|
||||||
|
Int64 (*GetGpuTimestampNs)(); // glGetInteger64v(GL_TIMESTAMP); 0 if unsupported
|
||||||
|
};
|
||||||
|
struct GlobalBackendFunctionsTable {
|
||||||
|
GLFunctionsTable GL;
|
||||||
|
void (*Present)();
|
||||||
|
// Optional: applies the app-requested eglSwapInterval to the native
|
||||||
|
// presentation path (null = backend keeps its own pacing policy).
|
||||||
|
void (*SetSwapInterval)(Int interval);
|
||||||
|
};
|
||||||
|
|
||||||
|
// THE DAMAGE OF THE PRESENT BEING APPLIED on this thread: the server's apply thread sets it
|
||||||
|
// around the backend's Present (from the present record), and a backend that can hand damage
|
||||||
|
// to its native present reads it there. Full whenever nothing set it.
|
||||||
|
const MG_Util::Damage::Region& CurrentPresentDamage();
|
||||||
|
void SetCurrentPresentDamage(const MG_Util::Damage::Region& damage);
|
||||||
|
|
||||||
|
extern GlobalBackendFunctionsTable gBackendFunctionsTable;
|
||||||
|
} // namespace MobileGL::MG_Backend
|
||||||
@@ -7,11 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "BackendObject.h"
|
#include "BackendObject.h"
|
||||||
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend {
|
namespace MobileGL::MG_Backend {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -23,146 +19,8 @@ namespace MobileGL::MG_Backend {
|
|||||||
std::thread::id CurrentThreadKey() {
|
std::thread::id CurrentThreadKey() {
|
||||||
return std::this_thread::get_id();
|
return std::this_thread::get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetFormatCapabilitySupportString(const FormatCapabilityCache& cache, SizeT targetIndex,
|
|
||||||
SizeT formatIndex, FormatCapability capability) {
|
|
||||||
if (HasFormatCapability(cache.FullCaps[targetIndex][formatIndex], capability)) return "Full";
|
|
||||||
if (HasFormatCapability(cache.CaveatCaps[targetIndex][formatIndex], capability)) return "Caveat";
|
|
||||||
return "None";
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT GetPrintedFormatNameWidth() {
|
|
||||||
SizeT width = 0;
|
|
||||||
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
|
||||||
const auto format = static_cast<TextureInternalFormat>(formatIndex);
|
|
||||||
width = std::max(width, MG_Util::ConvertTextureInternalFormatToString(format).size());
|
|
||||||
}
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT GetCapabilityColumnWidth(FormatCapability capability) {
|
|
||||||
SizeT width = std::strlen(GetFormatCapabilityName(capability));
|
|
||||||
width = std::max<SizeT>(width, std::strlen("Caveat"));
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
String BuildFormatCapabilityHeader(SizeT formatNameWidth) {
|
|
||||||
std::ostringstream line;
|
|
||||||
line << std::left << std::setw(static_cast<Int>(formatNameWidth)) << "";
|
|
||||||
for (FormatCapability capability : kReportedFormatCapabilities) {
|
|
||||||
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
|
||||||
<< GetFormatCapabilityName(capability);
|
|
||||||
}
|
|
||||||
return line.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
String BuildFormatCapabilityRow(const FormatCapabilityCache& cache, SizeT targetIndex, SizeT formatIndex,
|
|
||||||
SizeT formatNameWidth) {
|
|
||||||
const auto format = static_cast<TextureInternalFormat>(formatIndex);
|
|
||||||
std::ostringstream line;
|
|
||||||
line << std::left << std::setw(static_cast<Int>(formatNameWidth))
|
|
||||||
<< MG_Util::ConvertTextureInternalFormatToString(format);
|
|
||||||
for (FormatCapability capability : kReportedFormatCapabilities) {
|
|
||||||
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
|
||||||
<< GetFormatCapabilitySupportString(cache, targetIndex, formatIndex, capability);
|
|
||||||
}
|
|
||||||
return line.str();
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void FormatCapabilityCache::Clear() {
|
|
||||||
for (auto& row : FullCaps) {
|
|
||||||
row.fill(FormatCapabilityFlags{});
|
|
||||||
}
|
|
||||||
for (auto& row : CaveatCaps) {
|
|
||||||
row.fill(FormatCapabilityFlags{});
|
|
||||||
}
|
|
||||||
for (auto& row : SampleCounts) {
|
|
||||||
for (auto& counts : row) {
|
|
||||||
counts.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool HasFormatCapability(FormatCapabilityFlags caps, FormatCapability capability) {
|
|
||||||
return static_cast<Bool>(caps & capability);
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT GetFormatCapabilityTargetIndex(TextureTarget target) {
|
|
||||||
if (target == TextureTarget::Unknown || static_cast<Int>(target) < 0 ||
|
|
||||||
static_cast<SizeT>(target) >= kFormatCapabilityTextureTargetCount) {
|
|
||||||
return kFormatCapabilityTargetCount;
|
|
||||||
}
|
|
||||||
// An external texture is a 2D one wherever a format can go.
|
|
||||||
if (target == TextureTarget::External) return static_cast<SizeT>(TextureTarget::Texture2D);
|
|
||||||
return static_cast<SizeT>(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeT GetRenderbufferFormatCapabilityTargetIndex() {
|
|
||||||
return kFormatCapabilityRenderbufferTargetIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* GetFormatCapabilityName(FormatCapability capability) {
|
|
||||||
switch (capability) {
|
|
||||||
case FormatCapability::Creatable:
|
|
||||||
return "Creatable";
|
|
||||||
case FormatCapability::Sampled:
|
|
||||||
return "Sampled";
|
|
||||||
case FormatCapability::LinearFilter:
|
|
||||||
return "LinearFilter";
|
|
||||||
case FormatCapability::GenerateMipmap:
|
|
||||||
return "GenerateMipmap";
|
|
||||||
case FormatCapability::TextureGather:
|
|
||||||
return "TextureGather";
|
|
||||||
case FormatCapability::TextureShadow:
|
|
||||||
return "TextureShadow";
|
|
||||||
case FormatCapability::FramebufferRenderable:
|
|
||||||
return "FramebufferRenderable";
|
|
||||||
case FormatCapability::FramebufferLayered:
|
|
||||||
return "FramebufferLayered";
|
|
||||||
case FormatCapability::MultisampleTexture:
|
|
||||||
return "MultisampleTexture";
|
|
||||||
case FormatCapability::MultisampleRenderbuffer:
|
|
||||||
return "MultisampleRenderbuffer";
|
|
||||||
case FormatCapability::ColorAttachment:
|
|
||||||
return "ColorAttachment";
|
|
||||||
case FormatCapability::DepthAttachment:
|
|
||||||
return "DepthAttachment";
|
|
||||||
case FormatCapability::StencilAttachment:
|
|
||||||
return "StencilAttachment";
|
|
||||||
case FormatCapability::TextureBuffer:
|
|
||||||
return "TextureBuffer";
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
String GetFormatCapabilityTargetName(SizeT targetIndex) {
|
|
||||||
if (targetIndex == kFormatCapabilityRenderbufferTargetIndex) {
|
|
||||||
return "Renderbuffer";
|
|
||||||
}
|
|
||||||
if (targetIndex >= kFormatCapabilityTextureTargetCount) {
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrintFormatCapabilities(const FormatCapabilityCache& cache) {
|
|
||||||
const SizeT formatNameWidth = GetPrintedFormatNameWidth();
|
|
||||||
|
|
||||||
MGLOG_D("Backend format capabilities:");
|
|
||||||
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTargetCount; ++targetIndex) {
|
|
||||||
MGLOG_D("");
|
|
||||||
const String targetName = GetFormatCapabilityTargetName(targetIndex);
|
|
||||||
MGLOG_D("- %s", targetName.c_str());
|
|
||||||
const String header = BuildFormatCapabilityHeader(formatNameWidth);
|
|
||||||
MGLOG_D("%s", header.c_str());
|
|
||||||
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
|
||||||
const String row = BuildFormatCapabilityRow(cache, targetIndex, formatIndex, formatNameWidth);
|
|
||||||
MGLOG_D("%s", row.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool BackendObject::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
Bool BackendObject::InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
if (dpy == EGL_NO_DISPLAY) {
|
if (dpy == EGL_NO_DISPLAY) {
|
||||||
@@ -386,20 +244,6 @@ namespace MobileGL::MG_Backend {
|
|||||||
m_windowHandle = {};
|
m_windowHandle = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
MG_Util::Damage::Region& PresentDamageSlot() {
|
|
||||||
thread_local MG_Util::Damage::Region damage = MG_Util::Damage::Region::Full();
|
|
||||||
return damage;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
const MG_Util::Damage::Region& CurrentPresentDamage() {
|
|
||||||
return PresentDamageSlot();
|
|
||||||
}
|
|
||||||
void SetCurrentPresentDamage(const MG_Util::Damage::Region& damage) {
|
|
||||||
PresentDamageSlot() = damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool BackendObject::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
Bool BackendObject::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
|
||||||
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
if (!m_eglDisplayInitialized || m_eglDisplay != dpy) {
|
||||||
|
|||||||
@@ -9,238 +9,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <BackendCaps.h>
|
#include <BackendCaps.h>
|
||||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
|
#include <MG_Backend/SharedImageTypes.h>
|
||||||
#include <MG_Util/Damage/Damage.h>
|
#include <MG_Util/Damage/Damage.h>
|
||||||
#include <MG_Pipe/MGPipeHandles.h>
|
|
||||||
|
|
||||||
namespace MobileGL {
|
namespace MobileGL {
|
||||||
namespace MG_State::GLState {
|
|
||||||
class FramebufferObject;
|
|
||||||
class ITextureObject;
|
|
||||||
class RenderbufferObject;
|
|
||||||
} // namespace MG_State::GLState
|
|
||||||
|
|
||||||
namespace MG_Backend {
|
namespace MG_Backend {
|
||||||
// One endpoint of a glCopyImageSubData. GL 4.6 core 18.3.2 accepts GL_RENDERBUFFER
|
|
||||||
// alongside the ten whole-image texture targets, and a renderbuffer name lives in a
|
|
||||||
// namespace of its own - so an endpoint is a sum type, not an ITextureObject. At most
|
|
||||||
// one of the two pointers is set; neither is set when the name named nothing, which is
|
|
||||||
// the INVALID_VALUE the frontend validator reports.
|
|
||||||
struct CopyImageEndpoint {
|
|
||||||
SharedPtr<MG_State::GLState::ITextureObject> Texture;
|
|
||||||
SharedPtr<MG_State::GLState::RenderbufferObject> Renderbuffer;
|
|
||||||
MG_Pipe::MGPipeHandle TextureHandle = MG_Pipe::kMGPipeNullHandle;
|
|
||||||
MG_Pipe::MGPipeHandle RenderbufferHandle = MG_Pipe::kMGPipeNullHandle;
|
|
||||||
|
|
||||||
Bool IsRenderbuffer() const {
|
|
||||||
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
|
||||||
return Renderbuffer != nullptr;
|
|
||||||
}
|
|
||||||
Bool Exists() const {
|
|
||||||
if (!MG_Pipe::MGPipeHandleIsNull(TextureHandle)) return true;
|
|
||||||
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
|
||||||
return Texture != nullptr || Renderbuffer != nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Opaque backend fence-sync handle, created by GLFunctionsTable::FenceSync
|
|
||||||
// and released by GLFunctionsTable::DeleteSync.
|
|
||||||
using BackendSyncHandle = void*;
|
|
||||||
|
|
||||||
// Opaque backend timer-query handle, created by
|
|
||||||
// GLFunctionsTable::BeginTimeElapsedQuery / QueryCounterTimestamp and
|
|
||||||
// released by GLFunctionsTable::DeleteBackendQuery.
|
|
||||||
using BackendQueryHandle = void*;
|
|
||||||
|
|
||||||
struct GLFunctionsTable {
|
|
||||||
void (*DrawArrays)(GLenum mode, GLint first, GLsizei count);
|
|
||||||
void (*DrawElements)(GLenum mode, GLsizei count, GLenum type, const void* indices);
|
|
||||||
void (*DrawElementsBaseVertex)(GLenum mode, GLsizei count, GLenum type, const void* 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 (*DrawArraysInstancedBaseInstance)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
|
|
||||||
GLuint baseinstance);
|
|
||||||
void (*DrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
|
|
||||||
void (*DrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect);
|
|
||||||
void (*DrawArraysIndirect)(GLenum mode, const void* indirect);
|
|
||||||
void (*Clear)(GLbitfield mask);
|
|
||||||
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 (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
|
||||||
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
|
||||||
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 (*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);
|
|
||||||
// The by-name form: the destination is `texture`, whatever the units hold. `target` is
|
|
||||||
// the one the record carries (the texture's own 2D-class target).
|
|
||||||
void (*CopyTextureSubImage2D)(const SharedPtr<MG_State::GLState::ITextureObject>& texture, GLenum target,
|
|
||||||
GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
|
|
||||||
GLsizei height);
|
|
||||||
void (*CopyImageSubData)(const CopyImageEndpoint& src, GLenum srcTarget, GLint srcLevel, GLint srcX,
|
|
||||||
GLint srcY, GLint srcZ, const CopyImageEndpoint& dst, GLenum dstTarget,
|
|
||||||
GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth,
|
|
||||||
GLsizei srcHeight, GLsizei srcDepth);
|
|
||||||
void (*GenerateMipmap)(GLenum target);
|
|
||||||
// The by-name form, also used once the bound-target form has resolved its texture.
|
|
||||||
void (*GenerateTextureMipmap)(const SharedPtr<MG_State::GLState::ITextureObject>& texture, GLenum target);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
// The ONLY indexed query that is genuinely a backend one, and only for the pnames
|
|
||||||
// MG_Impl/GLImpl/Getter/GL_Getter.cpp does not already own. Every indexed pname that
|
|
||||||
// names FRONTEND state - the indexed buffer bindings, the per-unit texture/sampler
|
|
||||||
// bindings, the image-unit bindings, the viewport rectangles, the indexed capabilities
|
|
||||||
// - is answered in GL_Getter::GetIntegeri_v and never reaches this entry; the
|
|
||||||
// 64-bit and float/double widths are derived there from the same answer, which is why
|
|
||||||
// no GetInteger64i_v/GetFloati_v/GetDoublei_v table entry exists. In practice this
|
|
||||||
// leaves GL_MAX_COMPUTE_WORK_GROUP_COUNT / _SIZE (also asked directly by
|
|
||||||
// MG_Util/ShaderTranspiler/CompileEnv.cpp) plus whatever pname the frontend has no
|
|
||||||
// case for at all.
|
|
||||||
void (*GetIntegeri_v)(GLenum target, GLuint index, GLint* data);
|
|
||||||
// There is deliberately NO GetProgramiv entry: glGetProgramiv describes the program
|
|
||||||
// the APPLICATION wrote - link status, the transform-feedback mode, the compute local
|
|
||||||
// size - all of which are frontend link artifacts on ProgramObject, and
|
|
||||||
// MG_Impl/GLImpl/Program/GL_Program.cpp answers every one of them from there. Asking a
|
|
||||||
// backend would mean asking about a DIFFERENT program (a SPIRV-Cross-generated ESSL
|
|
||||||
// one, or a SPIR-V module), in a namespace the application never sees.
|
|
||||||
// The GL program interface (glGetProgramInterfaceiv / glGetProgramResource*) is NOT
|
|
||||||
// a backend query: it describes the program the application wrote, in the
|
|
||||||
// application's namespace, which neither backend program is in. It is answered
|
|
||||||
// entirely by MG_Impl/GLImpl/Program/ProgramInterface from the frontend reflection.
|
|
||||||
// Takes the block's GL NAME, not glShaderStorageBlockBinding's index. The index
|
|
||||||
// the application passes is the frontend interface-query enumeration's, and no
|
|
||||||
// backend shares that index space: DirectVulkan enumerates SPIR-V descriptor
|
|
||||||
// bindings and DirectGLES asks a real driver about SPIRV-Cross-generated ESSL.
|
|
||||||
// The name is the one coordinate all three agree on, so the frontend resolves the
|
|
||||||
// index against its own enumeration and each backend maps the name to its own.
|
|
||||||
void (*ShaderStorageBlockBinding)(GLuint program, const GLchar* storageBlockName,
|
|
||||||
GLuint storageBlockBinding);
|
|
||||||
// GL fence sync objects. All entries are optional (may be null); the
|
|
||||||
// frontend then falls back to always-signaled sync semantics.
|
|
||||||
// FenceSync may itself return null when the backend cannot create a
|
|
||||||
// fence right now (e.g. the calling thread does not own the backend
|
|
||||||
// context); the frontend treats such a sync as always signaled.
|
|
||||||
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); // true = signaled
|
|
||||||
// GL timer-query objects (GL_ARB_timer_query). All entries are
|
|
||||||
// optional (may be null); the frontend then falls back to zero
|
|
||||||
// results and reports GL_QUERY_COUNTER_BITS == 0.
|
|
||||||
// BeginTimeElapsedQuery / QueryCounterTimestamp may themselves
|
|
||||||
// return null when the backend cannot create a query right now;
|
|
||||||
// the frontend treats such a query as immediately available with
|
|
||||||
// a zero result.
|
|
||||||
// Dynamic support check: true only when the live backend can
|
|
||||||
// actually time at the moment of the call (extension / entry
|
|
||||||
// points / timestamp valid bits are known then, not at table
|
|
||||||
// init). Gates the advertised GL_QUERY_COUNTER_BITS.
|
|
||||||
Bool (*IsTimerQuerySupported)();
|
|
||||||
BackendQueryHandle (*BeginTimeElapsedQuery)(); // starts a TIME_ELAPSED span
|
|
||||||
void (*EndTimeElapsedQuery)(BackendQueryHandle query); // ends the span
|
|
||||||
BackendQueryHandle (*QueryCounterTimestamp)(); // glQueryCounter(GL_TIMESTAMP) one-shot
|
|
||||||
Bool (*IsQueryResultAvailable)(BackendQueryHandle query); // non-blocking
|
|
||||||
// Returns true when a final value was produced (*outNanoseconds
|
|
||||||
// written; the frontend may cache it and release the handle).
|
|
||||||
// Returns false when the result could not be obtained YET - e.g.
|
|
||||||
// a Vulkan wait that refuses to block on a not-yet-submitted
|
|
||||||
// frame serial - in which case the frontend must keep the handle
|
|
||||||
// and leave the query readable later.
|
|
||||||
Bool (*GetQueryResult64)(BackendQueryHandle query, Bool wait, Uint64* outNanoseconds);
|
|
||||||
void (*DeleteBackendQuery)(BackendQueryHandle query);
|
|
||||||
// GL_SAMPLES_PASSED occlusion queries (optional; null = unsupported,
|
|
||||||
// the frontend then rejects the target). Results/deletion flow through
|
|
||||||
// GetQueryResult64 / DeleteBackendQuery like timer queries.
|
|
||||||
BackendQueryHandle (*BeginOcclusionQuery)();
|
|
||||||
void (*EndOcclusionQuery)(BackendQueryHandle query);
|
|
||||||
// Transform feedback primitive queries backed by real GPU query pools
|
|
||||||
// (optional; null = frontend falls back to CPU accounting).
|
|
||||||
BackendQueryHandle (*BeginXfbPrimitivesQuery)(Bool generated);
|
|
||||||
void (*EndXfbPrimitivesQuery)(BackendQueryHandle query);
|
|
||||||
// Whether GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN should be answered from the
|
|
||||||
// frontend's own accounting wherever that accounting is exact - a capture with no
|
|
||||||
// geometry stage - instead of from the query above. Set by DirectGLES, whose result
|
|
||||||
// is whatever the ES driver's PRIMITIVES_WRITTEN counter says: Adreno reports twice
|
|
||||||
// the written count for a vertex-only capture that follows a large render pass,
|
|
||||||
// where the desktop-exact answer is the one the frontend already computed. Defaults
|
|
||||||
// to false, so a backend that never sets it keeps using its GPU result.
|
|
||||||
Bool PrefersCpuXfbPrimitiveAccounting = false;
|
|
||||||
// Transform feedback capture spans, for backends whose own GL/ES driver
|
|
||||||
// performs the capture (DirectGLES). Both optional; null means the backend
|
|
||||||
// drives capture from its draw recording instead (DirectVulkan). End is
|
|
||||||
// called while the frontend capture state is still active, so the backend
|
|
||||||
// can still see the capture program and buffer bindings.
|
|
||||||
// GL_PATCH_VERTICES; ES 3.2 spells it the same way.
|
|
||||||
void (*PatchParameteri)(GLenum pname, GLint value);
|
|
||||||
void (*BeginTransformFeedback)(GLenum primitiveMode);
|
|
||||||
void (*EndTransformFeedback)();
|
|
||||||
// ARB_transform_feedback2. A backend that leaves these null keeps the single
|
|
||||||
// implicit capture span the frontend has always modelled; the frontend state
|
|
||||||
// (paused flag, per-object bindings) is tracked either way.
|
|
||||||
void (*PauseTransformFeedback)();
|
|
||||||
void (*ResumeTransformFeedback)();
|
|
||||||
void (*BindTransformFeedback)(GLuint name);
|
|
||||||
void (*DeleteTransformFeedback)(GLuint name);
|
|
||||||
Int64 (*GetGpuTimestampNs)(); // glGetInteger64v(GL_TIMESTAMP); 0 if unsupported
|
|
||||||
};
|
|
||||||
struct GlobalBackendFunctionsTable {
|
|
||||||
GLFunctionsTable GL;
|
|
||||||
void (*Present)();
|
|
||||||
// Optional: applies the app-requested eglSwapInterval to the native
|
|
||||||
// presentation path (null = backend keeps its own pacing policy).
|
|
||||||
void (*SetSwapInterval)(Int interval);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class WindowBackend {
|
enum class WindowBackend {
|
||||||
Android,
|
Android,
|
||||||
X11,
|
X11,
|
||||||
@@ -258,58 +32,6 @@ namespace MobileGL {
|
|||||||
Uint32 Height = 0;
|
Uint32 Height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SHARED IMAGES (docs/archive/notes/anland/plan-ahb-dmabuf.md): server-allocated colour
|
|
||||||
// buffers exported to clients as dma-buf descriptors.
|
|
||||||
//
|
|
||||||
// The server-side view of one image, as a backend sees it: `NativeBuffer` is the image's
|
|
||||||
// AHardwareBuffer (null where there is none), `Fourcc` a DRM fourcc - ABGR8888 (R, G, B, A in
|
|
||||||
// memory, GL RGBA8) or XBGR8888 (alpha ignored); ARGB8888 / XRGB8888 images are stored the
|
|
||||||
// same way (SharedImageRegistry.h says why), so a backend binds every one as RGBA8.
|
|
||||||
struct SharedImageView {
|
|
||||||
Uint64 Id = 0;
|
|
||||||
Uint32 Width = 0;
|
|
||||||
Uint32 Height = 0;
|
|
||||||
Uint32 Fourcc = 0;
|
|
||||||
void* NativeBuffer = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The client-side answer of an allocation: the image's id and its exported descriptor
|
|
||||||
// (`Fd`, owned by the caller), with the plane layout a linux-dmabuf wl_buffer is created with.
|
|
||||||
struct SharedImageExport {
|
|
||||||
Uint64 Id = 0;
|
|
||||||
int Fd = -1;
|
|
||||||
Uint32 Width = 0;
|
|
||||||
Uint32 Height = 0;
|
|
||||||
Uint32 Fourcc = 0;
|
|
||||||
Uint32 Stride = 0;
|
|
||||||
Uint32 Offset = 0;
|
|
||||||
Uint64 Modifier = 0;
|
|
||||||
// A YUV image's Cb Cr plane: in the same descriptor, at this offset and pitch.
|
|
||||||
Uint32 Plane1Stride = 0;
|
|
||||||
Uint32 Plane1Offset = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// An import of a two-plane (YUV) dma-buf: where its planes are in the one descriptor, and
|
|
||||||
// EGL_EXT_image_dma_buf_import's colour hints (0 = not given).
|
|
||||||
struct SharedImageImportLayout {
|
|
||||||
Uint32 PlaneCount = 1;
|
|
||||||
Uint32 Offset[2] = {0, 0};
|
|
||||||
Uint32 Pitch[2] = {0, 0};
|
|
||||||
Uint32 ColorSpace = 0;
|
|
||||||
Uint32 Range = 0;
|
|
||||||
Uint32 SitingX = 0;
|
|
||||||
Uint32 SitingY = 0;
|
|
||||||
// The DRM format modifier the import named; HasModifier false = none (the implicit one).
|
|
||||||
Bool HasModifier = false;
|
|
||||||
Uint64 Modifier = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// THE DAMAGE OF THE PRESENT BEING APPLIED on this thread: the server's apply thread sets it
|
|
||||||
// around the backend's Present (from the present record), and a backend that can hand damage
|
|
||||||
// to its native present reads it there. Full whenever nothing set it.
|
|
||||||
const MG_Util::Damage::Region& CurrentPresentDamage();
|
|
||||||
void SetCurrentPresentDamage(const MG_Util::Damage::Region& damage);
|
|
||||||
|
|
||||||
class BackendObject {
|
class BackendObject {
|
||||||
public:
|
public:
|
||||||
virtual ~BackendObject() = default;
|
virtual ~BackendObject() = default;
|
||||||
@@ -582,6 +304,5 @@ namespace MobileGL {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern UniquePtr<BackendObject>& pActiveBackendObject;
|
extern UniquePtr<BackendObject>& pActiveBackendObject;
|
||||||
extern GlobalBackendFunctionsTable gBackendFunctionsTable;
|
|
||||||
} // namespace MG_Backend
|
} // namespace MG_Backend
|
||||||
} // namespace MobileGL
|
} // namespace MobileGL
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include <MG_Backend/BackendObject.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
#include "MagmaSession.h"
|
#include "MagmaSession.h"
|
||||||
#include "Renderer/VulkanRenderer.h"
|
#include "Renderer/VulkanRenderer.h"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/FormatCapabilities.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 <BackendCaps.h>
|
||||||
|
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend {
|
||||||
|
namespace {
|
||||||
|
const char* GetFormatCapabilitySupportString(const FormatCapabilityCache& cache, SizeT targetIndex,
|
||||||
|
SizeT formatIndex, FormatCapability capability) {
|
||||||
|
if (HasFormatCapability(cache.FullCaps[targetIndex][formatIndex], capability)) return "Full";
|
||||||
|
if (HasFormatCapability(cache.CaveatCaps[targetIndex][formatIndex], capability)) return "Caveat";
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT GetPrintedFormatNameWidth() {
|
||||||
|
SizeT width = 0;
|
||||||
|
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
||||||
|
const auto format = static_cast<TextureInternalFormat>(formatIndex);
|
||||||
|
width = std::max(width, MG_Util::ConvertTextureInternalFormatToString(format).size());
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT GetCapabilityColumnWidth(FormatCapability capability) {
|
||||||
|
SizeT width = std::strlen(GetFormatCapabilityName(capability));
|
||||||
|
width = std::max<SizeT>(width, std::strlen("Caveat"));
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
String BuildFormatCapabilityHeader(SizeT formatNameWidth) {
|
||||||
|
std::ostringstream line;
|
||||||
|
line << std::left << std::setw(static_cast<Int>(formatNameWidth)) << "";
|
||||||
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
|
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
||||||
|
<< GetFormatCapabilityName(capability);
|
||||||
|
}
|
||||||
|
return line.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
String BuildFormatCapabilityRow(const FormatCapabilityCache& cache, SizeT targetIndex, SizeT formatIndex,
|
||||||
|
SizeT formatNameWidth) {
|
||||||
|
const auto format = static_cast<TextureInternalFormat>(formatIndex);
|
||||||
|
std::ostringstream line;
|
||||||
|
line << std::left << std::setw(static_cast<Int>(formatNameWidth))
|
||||||
|
<< MG_Util::ConvertTextureInternalFormatToString(format);
|
||||||
|
for (FormatCapability capability : kReportedFormatCapabilities) {
|
||||||
|
line << " | " << std::left << std::setw(static_cast<Int>(GetCapabilityColumnWidth(capability)))
|
||||||
|
<< GetFormatCapabilitySupportString(cache, targetIndex, formatIndex, capability);
|
||||||
|
}
|
||||||
|
return line.str();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void FormatCapabilityCache::Clear() {
|
||||||
|
for (auto& row : FullCaps) {
|
||||||
|
row.fill(FormatCapabilityFlags{});
|
||||||
|
}
|
||||||
|
for (auto& row : CaveatCaps) {
|
||||||
|
row.fill(FormatCapabilityFlags{});
|
||||||
|
}
|
||||||
|
for (auto& row : SampleCounts) {
|
||||||
|
for (auto& counts : row) {
|
||||||
|
counts.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool HasFormatCapability(FormatCapabilityFlags caps, FormatCapability capability) {
|
||||||
|
return static_cast<Bool>(caps & capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT GetFormatCapabilityTargetIndex(TextureTarget target) {
|
||||||
|
if (target == TextureTarget::Unknown || static_cast<Int>(target) < 0 ||
|
||||||
|
static_cast<SizeT>(target) >= kFormatCapabilityTextureTargetCount) {
|
||||||
|
return kFormatCapabilityTargetCount;
|
||||||
|
}
|
||||||
|
// An external texture is a 2D one wherever a format can go.
|
||||||
|
if (target == TextureTarget::External) return static_cast<SizeT>(TextureTarget::Texture2D);
|
||||||
|
return static_cast<SizeT>(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeT GetRenderbufferFormatCapabilityTargetIndex() {
|
||||||
|
return kFormatCapabilityRenderbufferTargetIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetFormatCapabilityName(FormatCapability capability) {
|
||||||
|
switch (capability) {
|
||||||
|
case FormatCapability::Creatable:
|
||||||
|
return "Creatable";
|
||||||
|
case FormatCapability::Sampled:
|
||||||
|
return "Sampled";
|
||||||
|
case FormatCapability::LinearFilter:
|
||||||
|
return "LinearFilter";
|
||||||
|
case FormatCapability::GenerateMipmap:
|
||||||
|
return "GenerateMipmap";
|
||||||
|
case FormatCapability::TextureGather:
|
||||||
|
return "TextureGather";
|
||||||
|
case FormatCapability::TextureShadow:
|
||||||
|
return "TextureShadow";
|
||||||
|
case FormatCapability::FramebufferRenderable:
|
||||||
|
return "FramebufferRenderable";
|
||||||
|
case FormatCapability::FramebufferLayered:
|
||||||
|
return "FramebufferLayered";
|
||||||
|
case FormatCapability::MultisampleTexture:
|
||||||
|
return "MultisampleTexture";
|
||||||
|
case FormatCapability::MultisampleRenderbuffer:
|
||||||
|
return "MultisampleRenderbuffer";
|
||||||
|
case FormatCapability::ColorAttachment:
|
||||||
|
return "ColorAttachment";
|
||||||
|
case FormatCapability::DepthAttachment:
|
||||||
|
return "DepthAttachment";
|
||||||
|
case FormatCapability::StencilAttachment:
|
||||||
|
return "StencilAttachment";
|
||||||
|
case FormatCapability::TextureBuffer:
|
||||||
|
return "TextureBuffer";
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetFormatCapabilityTargetName(SizeT targetIndex) {
|
||||||
|
if (targetIndex == kFormatCapabilityRenderbufferTargetIndex) {
|
||||||
|
return "Renderbuffer";
|
||||||
|
}
|
||||||
|
if (targetIndex >= kFormatCapabilityTextureTargetCount) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
return MG_Util::ConvertTextureTargetToString(static_cast<TextureTarget>(targetIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintFormatCapabilities(const FormatCapabilityCache& cache) {
|
||||||
|
const SizeT formatNameWidth = GetPrintedFormatNameWidth();
|
||||||
|
|
||||||
|
MGLOG_D("Backend format capabilities:");
|
||||||
|
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTargetCount; ++targetIndex) {
|
||||||
|
MGLOG_D("");
|
||||||
|
const String targetName = GetFormatCapabilityTargetName(targetIndex);
|
||||||
|
MGLOG_D("- %s", targetName.c_str());
|
||||||
|
const String header = BuildFormatCapabilityHeader(formatNameWidth);
|
||||||
|
MGLOG_D("%s", header.c_str());
|
||||||
|
for (SizeT formatIndex = 0; formatIndex < kFormatCapabilityFormatCount; ++formatIndex) {
|
||||||
|
const String row = BuildFormatCapabilityRow(cache, targetIndex, formatIndex, formatNameWidth);
|
||||||
|
MGLOG_D("%s", row.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace MobileGL::MG_Backend
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// MobileGL - MobileGL/MG_Backend/SharedImageTypes.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>
|
||||||
|
|
||||||
|
namespace MobileGL::MG_Backend {
|
||||||
|
// SHARED IMAGES (docs/archive/notes/anland/plan-ahb-dmabuf.md): server-allocated colour
|
||||||
|
// buffers exported to clients as dma-buf descriptors.
|
||||||
|
//
|
||||||
|
// The server-side view of one image, as a backend sees it: `NativeBuffer` is the image's
|
||||||
|
// AHardwareBuffer (null where there is none), `Fourcc` a DRM fourcc - ABGR8888 (R, G, B, A in
|
||||||
|
// memory, GL RGBA8) or XBGR8888 (alpha ignored); ARGB8888 / XRGB8888 images are stored the
|
||||||
|
// same way (SharedImageRegistry.h says why), so a backend binds every one as RGBA8.
|
||||||
|
struct SharedImageView {
|
||||||
|
Uint64 Id = 0;
|
||||||
|
Uint32 Width = 0;
|
||||||
|
Uint32 Height = 0;
|
||||||
|
Uint32 Fourcc = 0;
|
||||||
|
void* NativeBuffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The client-side answer of an allocation: the image's id and its exported descriptor
|
||||||
|
// (`Fd`, owned by the caller), with the plane layout a linux-dmabuf wl_buffer is created with.
|
||||||
|
struct SharedImageExport {
|
||||||
|
Uint64 Id = 0;
|
||||||
|
int Fd = -1;
|
||||||
|
Uint32 Width = 0;
|
||||||
|
Uint32 Height = 0;
|
||||||
|
Uint32 Fourcc = 0;
|
||||||
|
Uint32 Stride = 0;
|
||||||
|
Uint32 Offset = 0;
|
||||||
|
Uint64 Modifier = 0;
|
||||||
|
// A YUV image's Cb Cr plane: in the same descriptor, at this offset and pitch.
|
||||||
|
Uint32 Plane1Stride = 0;
|
||||||
|
Uint32 Plane1Offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An import of a two-plane (YUV) dma-buf: where its planes are in the one descriptor, and
|
||||||
|
// EGL_EXT_image_dma_buf_import's colour hints (0 = not given).
|
||||||
|
struct SharedImageImportLayout {
|
||||||
|
Uint32 PlaneCount = 1;
|
||||||
|
Uint32 Offset[2] = {0, 0};
|
||||||
|
Uint32 Pitch[2] = {0, 0};
|
||||||
|
Uint32 ColorSpace = 0;
|
||||||
|
Uint32 Range = 0;
|
||||||
|
Uint32 SitingX = 0;
|
||||||
|
Uint32 SitingY = 0;
|
||||||
|
// The DRM format modifier the import named; HasModifier false = none (the implicit one).
|
||||||
|
Bool HasModifier = false;
|
||||||
|
Uint64 Modifier = 0;
|
||||||
|
};
|
||||||
|
} // namespace MobileGL::MG_Backend
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
#include "GL_Sync.h"
|
#include "GL_Sync.h"
|
||||||
#include <MG_Backend/BackendObjects.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
#include <MG_State/GLState/BufferState/BufferObject.h>
|
#include <MG_State/GLState/BufferState/BufferObject.h>
|
||||||
#include <MG_Impl/Pipe/PipeFill.h>
|
#include <MG_Impl/Pipe/PipeFill.h>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
#include <MG_Backend/BackendObject.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
#include <MG_Pipe/MGPipeTypes.h>
|
#include <MG_Pipe/MGPipeTypes.h>
|
||||||
#include <MG_Pipe/MGPipeValueTypes.h>
|
#include <MG_Pipe/MGPipeValueTypes.h>
|
||||||
#include <MG_Pipe/PipeVerbSink.h>
|
#include <MG_Pipe/PipeVerbSink.h>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
// the pixels the draw produced or the case fails.
|
// the pixels the draw produced or the case fails.
|
||||||
//
|
//
|
||||||
// 3. THE FIRST CASE ENDS WITH EndFrame(), DELIBERATELY. `Present` has ZERO call sites in
|
// 3. THE FIRST CASE ENDS WITH EndFrame(), DELIBERATELY. `Present` has ZERO call sites in
|
||||||
// MG_Impl - it is reached only through EGLImpl.cpp:178 -> BackendObject.cpp:396 - so a
|
// MG_Impl - it is reached only through eglSwapBuffers -> BackendObject::SwapEGLBuffers - so a
|
||||||
// scenario that never swaps never touches it, and B would then exercise a STRICT SUBSET of
|
// scenario that never swaps never touches it, and B would then exercise a STRICT SUBSET of
|
||||||
// what ClearThenReadPixelsScenario already covers. BRIEF-P5 4.B lists Present(67) among the
|
// what ClearThenReadPixelsScenario already covers. BRIEF-P5 4.B lists Present(67) among the
|
||||||
// catalogue rows this target needs, so the frame boundary is here on purpose: B is A's slot
|
// catalogue rows this target needs, so the frame boundary is here on purpose: B is A's slot
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
// G5b: the verb enum, the verb classes and their may-read field masks.
|
// G5b: the verb enum, the verb classes and their may-read field masks.
|
||||||
//
|
//
|
||||||
// GENERATED by scripts/gen_pipe.py from FillPoints.def, Coverage.def and MG_Backend/BackendObject.h - DO NOT EDIT.
|
// GENERATED by scripts/gen_pipe.py from FillPoints.def, Coverage.def and MG_Backend/BackendFunctions.h - DO NOT EDIT.
|
||||||
// Regenerate with `python3 scripts/gen_pipe.py`; CI runs it and diffs the result.
|
// Regenerate with `python3 scripts/gen_pipe.py`; CI runs it and diffs the result.
|
||||||
// This file is included from MG_Pipe/MGPipe.h inside namespace MobileGL::MG_Pipe.
|
// This file is included from MG_Pipe/MGPipe.h inside namespace MobileGL::MG_Pipe.
|
||||||
|
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
|
|
||||||
Bool BackendObject_Remote::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
Bool BackendObject_Remote::SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) {
|
||||||
// NOT FORWARDED, and this is the one that must not be. The base implementation's last
|
// NOT FORWARDED, and this is the one that must not be. The base implementation's last
|
||||||
// act is GetBackendFunctions().Present() (BackendObject.cpp:396) - which is this
|
// act is GetBackendFunctions().Present() - which is this
|
||||||
// client's class-B Present EMITTER, the only route by which Present is reached at all
|
// client's class-B Present EMITTER, the only route by which Present is reached at all
|
||||||
// (it has zero MG_Impl call sites). Calling Server::ServerSwapEGLBuffers would present
|
// (it has zero MG_Impl call sites). Calling Server::ServerSwapEGLBuffers would present
|
||||||
// on the server directly and put no record on the wire, which is the shape every gate
|
// on the server directly and put no record on the wire, which is the shape every gate
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
#include <MG_Backend/BackendObject.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
// P5b: the clear discriminants below alias MGPipeTypes.h's (CONTRACT-P5B.md f1). The header
|
// P5b: the clear discriminants below alias MGPipeTypes.h's (CONTRACT-P5B.md f1). The header
|
||||||
// was already in this file's closure through BackendObject.h's neighbours; naming it makes
|
// was already in this file's closure through BackendObject.h's neighbours; naming it makes
|
||||||
// the dependency the aliases have explicit.
|
// the dependency the aliases have explicit.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
#include <Config.h>
|
#include <Config.h>
|
||||||
#include <MG_Backend/BackendObject.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
|
|
||||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
#include <MG_Pipe/MGPipeTypes.h>
|
#include <MG_Pipe/MGPipeTypes.h>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#include "Init.h"
|
#include "Init.h"
|
||||||
#include <Config.h>
|
#include <Config.h>
|
||||||
|
|
||||||
#include <MG_Backend/BackendObjects.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||||
#include <MG_Impl/GLImpl/Query/GL_Query.h>
|
#include <MG_Impl/GLImpl/Query/GL_Query.h>
|
||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include "Includes.h"
|
#include "Includes.h"
|
||||||
#include "Init.h"
|
#include "Init.h"
|
||||||
#include <MG_Backend/BackendObjects.h>
|
#include <MG_Backend/BackendFunctions.h>
|
||||||
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
|
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
|
||||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||||
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
|
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"allcaps_comment_lines": 2253,
|
"allcaps_comment_lines": 2253,
|
||||||
"line_citations": 159,
|
"line_citations": 156,
|
||||||
"long_comment_excess_lines": 8895,
|
"long_comment_excess_lines": 8895,
|
||||||
"non_english_comment_lines": 20,
|
"non_english_comment_lines": 20,
|
||||||
"planning_code_comment_lines": 3188
|
"planning_code_comment_lines": 3188
|
||||||
|
|||||||
+3
-3
@@ -45,7 +45,7 @@ REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
PIPE_DIR = os.path.join(REPO_ROOT, "MobileGL", "MG_Pipe")
|
PIPE_DIR = os.path.join(REPO_ROOT, "MobileGL", "MG_Pipe")
|
||||||
GENERATED_DIR = os.path.join(PIPE_DIR, "generated")
|
GENERATED_DIR = os.path.join(PIPE_DIR, "generated")
|
||||||
INVENTORY = os.path.join(REPO_ROOT, "scripts", "data", "backend_read_inventory.md")
|
INVENTORY = os.path.join(REPO_ROOT, "scripts", "data", "backend_read_inventory.md")
|
||||||
FUNCTION_TABLE_HEADER = os.path.join(REPO_ROOT, "MobileGL", "MG_Backend", "BackendObject.h")
|
FUNCTION_TABLE_HEADER = os.path.join(REPO_ROOT, "MobileGL", "MG_Backend", "BackendFunctions.h")
|
||||||
|
|
||||||
GENERATED_BANNER = """// MobileGL - MobileGL/MG_Pipe/generated/{name}
|
GENERATED_BANNER = """// MobileGL - MobileGL/MG_Pipe/generated/{name}
|
||||||
// Copyright (c) 2025-2026 MobileGL-Dev
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
||||||
@@ -227,7 +227,7 @@ MEMCMP_FALLBACK_TYPES = set()
|
|||||||
|
|
||||||
# Where the structs named in PipeFields.def are declared: the payload header, the value
|
# Where the structs named in PipeFields.def are declared: the payload header, the value
|
||||||
# header, the host-span header, the backend capability header (DynamicBackendParameters, the
|
# header, the host-span header, the backend capability header (DynamicBackendParameters, the
|
||||||
# caps block) and the backend object header.
|
# caps block) and the backend function table header.
|
||||||
FIELD_LIST_STRUCT_HEADERS = [
|
FIELD_LIST_STRUCT_HEADERS = [
|
||||||
os.path.join(PIPE_DIR, "MGPipeTypes.h"),
|
os.path.join(PIPE_DIR, "MGPipeTypes.h"),
|
||||||
os.path.join(PIPE_DIR, "MGPipeValueTypes.h"),
|
os.path.join(PIPE_DIR, "MGPipeValueTypes.h"),
|
||||||
@@ -1344,7 +1344,7 @@ def gen_fill_points(accessors, sticky, verbs, classes, fields):
|
|||||||
words = max(2, (len(accessors) + 63) // 64)
|
words = max(2, (len(accessors) + 63) // 64)
|
||||||
sticky_names = [name for name, _ in sticky]
|
sticky_names = [name for name, _ in sticky]
|
||||||
out = [banner("PipeFillPoints.inc", "G5b: the verb enum, the verb classes and their may-read field masks.",
|
out = [banner("PipeFillPoints.inc", "G5b: the verb enum, the verb classes and their may-read field masks.",
|
||||||
"FillPoints.def, Coverage.def and MG_Backend/BackendObject.h")]
|
"FillPoints.def, Coverage.def and MG_Backend/BackendFunctions.h")]
|
||||||
out.append("""// One verb per function-pointer member of MG_Backend::GLFunctionsTable, in declaration
|
out.append("""// One verb per function-pointer member of MG_Backend::GLFunctionsTable, in declaration
|
||||||
// order, so the enum IS the table's member list. MG_Impl spells MGP_FILL(Verb) before every
|
// order, so the enum IS the table's member list. MG_Impl spells MGP_FILL(Verb) before every
|
||||||
// call through the table; MGPipeFillForVerb fills exactly the fields of the verb's class
|
// call through the table; MGPipeFillForVerb fills exactly the fields of the verb's class
|
||||||
|
|||||||
Reference in New Issue
Block a user