mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 12:18:30 +09:00
A per-draw CPU profile of a real Minecraft frame (perf on the render thread, which sits at 100% of one core on both backends) said the deficit is translation overhead, not the GPU, and named where it goes. This removes the largest items it found, on both backends and in the shared frontend they both feed. The single biggest one was not translation at all: IsBackendContextCurrentOnThisThread called eglGetCurrentContext on every invocation, and glvnd answers that with a getpid() fork check - a real syscall. The predicate sits two and three deep in every draw (the deferred-release drain, the global-UBO ring availability check, and the ring allocation), so it accounted for 16.3% of the render thread. EGL is still the ground truth, but re-verifying it once per thread per frame catches an external migration at the next frame boundary rather than the next call, which recovers the same bookkeeping. Texture uploads now carry a dirty region instead of a per-level flag. Minecraft animates atlas sprites with 16x16 glTexSubImage2D calls into a 1024x512 atlas and respecifies the lightmap every frame; a per-level flag turned each of those into a full-level re-upload - about 3.6 MB a frame of texels nobody changed. MipmapStorage accumulates the written box, Espryt uploads it with UNPACK_ROW_LENGTH striding into the level shadow, and Magma stages just that box. The box is a union, not a range list: repeated writes to one level widen it and it degrades to exactly the old whole-level upload, which is the honest worst case. glBufferData(NULL) is the orphaning idiom, and the backend was answering it by uploading the stale CPU shadow - turning a rename the driver does for free into a full synchronized upload. BufferObject now records that a NULL respecify leaves the store undefined, and the upload is skipped until content is actually written. The rest are smaller and of a kind: the deferred-release queue is probed without taking its mutex, the UBO ring waits on the frame fence that frees the space it needs instead of draining the whole pipeline with glFinish at the size cap, VAO binds go through a shadow so a draw's second bind of the same object does not reach the driver, the per-draw clean-texture probe short-circuits on the content version before rebuilding shape info, glUniform drops byte-identical writes (which otherwise dirty the whole UBO for the next draw), re-binding the texture or VAO a slot already holds no longer bumps the generation counters a backend fast path is keyed on, and the texture validators stopped taking shared_ptr by value. On Magma: descriptor-set reuse keeps four entries instead of one, because draws alternating between two programs - the chunk/entity ping-pong - thrashed a single slot into a full re-allocate and re-write every draw; a DynamicDraw buffer whose contents survive two frame boundaries is promoted to resident storage instead of being re-copied into the per-frame arena forever; and sampled-read barriers name only the shader stages whose device feature is enabled, which also removes a latent VUID violation (ALL_GRAPHICS names geometry and tessellation stages a device need not have). Measured with the Minecraft rig (render distance 32, p50 fps, same machine, single sample each): vanilla 1.21.1 Espryt 10.8 -> 36.3 and Magma 31.3 -> 44.6; 26.2 snapshot Magma 114.5 -> 210.5. Fabric+Sodium moved inside noise on Magma (854 -> 766) with the native baseline itself moving 838 -> 1031 between the two sessions, so treat that cell as unresolved rather than a regression measured. Unit tests 421/421. The CTS A/B was not run: these numbers and the test suite are the whole of the evidence, and a conformance regression would not have been caught here.
45 lines
2.9 KiB
C++
45 lines
2.9 KiB
C++
// MobileGL - MobileGL/MG_Impl/GLImpl/Texture/Validators.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 "MG_State/GLState/TextureState/TextureEnum.h"
|
|
#include "MG_Util/Types.h"
|
|
#include <Includes.h>
|
|
#include <MG_State/GLState/TextureState/TextureObject.h>
|
|
|
|
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
|
Bool ValidateTextureTarget(TextureTarget target);
|
|
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
|
|
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
|
|
Bool ValidateTextureInputFormat(TextureInputFormat format);
|
|
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
|
Bool ValidateTextureLevelNumber(Int level);
|
|
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
|
Bool ValidateTextureSizeRange(Int width, Int height, Int depth);
|
|
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
|
Bool ValidateTextureBorderNumber(Int border);
|
|
Bool IsIntegerColorInputFormat(TextureInputFormat format);
|
|
Bool IsIntegerColorInternalFormat(TextureInternalFormat internalFormat);
|
|
Bool ValidateClientFormatTypePairing(TextureInputFormat format, TexturePixelDataType type);
|
|
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
|
|
TextureInternalFormat internalFormat,
|
|
TexturePixelDataType type);
|
|
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
|
|
Bool ValidateTextureObject(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject);
|
|
// Rejects the per-target default texture objects (name 0) with GL_INVALID_OPERATION for entry
|
|
// points that require a GenTextures-created texture, e.g. TexStorage* ("An INVALID_OPERATION
|
|
// error is generated if zero is bound to target", ARB_texture_storage).
|
|
Bool ValidateTextureNotDefault(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
|
const char* caller);
|
|
Bool ValidateTextureTargetUniformity(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
|
TextureTarget target);
|
|
Bool ValidateTextureSubImageOffsets(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, Int xoffset,
|
|
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
|
|
Bool ValidateBaseInternalFormatMatch(TextureInternalFormat format1, TextureInternalFormat format2);
|
|
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl
|