mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Docs, Chore] (docs, tools, MobileGL, scripts, CONTRIBUTING.md, .gitignore): translate the documentation and use US spelling
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
|
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
/build
|
/build
|
||||||
|
|||||||
+7
-7
@@ -16,10 +16,10 @@ Commands below use `python3`. On Windows, run `python` instead.
|
|||||||
- **Subject only by default.** Add `- ` detail lines only when a detail really needs to be in the commit message. Leave one blank line after the subject. A detail that wraps continues on at most two lines indented by two spaces. No paragraphs and no trailers.
|
- **Subject only by default.** Add `- ` detail lines only when a detail really needs to be in the commit message. Leave one blank line after the subject. A detail that wraps continues on at most two lines indented by two spaces. No paragraphs and no trailers.
|
||||||
- **Content** after `): ` is at most 72 characters of plain English in the imperative mood ("flush once per frame", not "flushes" or "flushed").
|
- **Content** after `): ` is at most 72 characters of plain English in the imperative mood ("flush once per frame", not "flushes" or "flushed").
|
||||||
- **Type** is one or more of these, comma-separated (`[Fix, Test]`):
|
- **Type** is one or more of these, comma-separated (`[Fix, Test]`):
|
||||||
- `Feat`: new behaviour.
|
- `Feat`: new behavior.
|
||||||
- `Fix`: corrects behaviour.
|
- `Fix`: corrects behavior.
|
||||||
- `Perf`: faster or lighter, same behaviour.
|
- `Perf`: faster or lighter, same behavior.
|
||||||
- `Refactor`: restructures code, same behaviour.
|
- `Refactor`: restructures code, same behavior.
|
||||||
- `Test`: tests only.
|
- `Test`: tests only.
|
||||||
- `Docs`: documentation and comments only.
|
- `Docs`: documentation and comments only.
|
||||||
- `Build`: CMake, Gradle, toolchains.
|
- `Build`: CMake, Gradle, toolchains.
|
||||||
@@ -43,12 +43,12 @@ Example:
|
|||||||
|
|
||||||
## Comments, strings and documentation
|
## Comments, strings and documentation
|
||||||
|
|
||||||
- Code, comments, log strings and commit messages are in English. Documentation may be in Chinese or English.
|
- Code, comments, log strings and commit messages are in English, and documentation may be in English. American spelling is preferred in all of them: documentation, comments, strings and identifiers (color, behavior, center, cancel, initialize, normalize, organize, analyze, license, defense, artifact, modeling, labeled, gray, honor, neighbor, catalog).
|
||||||
- A comment states what the code does now and why, in a few lines. Rationale longer than about 15 lines belongs in a design document under `docs/`, with a one-line pointer in the code.
|
- A comment states what the code does now and why, in a few lines. Rationale longer than about 15 lines belongs in a design document under `docs/`, with a one-line pointer in the code.
|
||||||
- In code and comments, cite a symbol, file or section, never a line number: `ARCHITECTURE.md §1.3`, `VulkanRenderer::BeginFrame()`. Documents may keep `file:line` citations; the documentation citation check resolves them.
|
- In code and comments, cite a symbol, file or section, never a line number: `ARCHITECTURE.md §1.3`, `VulkanRenderer::BeginFrame()`. Documents may keep `file:line` citations; the documentation citation check resolves them.
|
||||||
- State the rule, not its history. No "previously" or "after review", and no planning ids in comments, strings, identifiers or file names.
|
- State the rule, not its history. No "previously" or "after review", and no planning ids in comments, strings, identifiers or file names.
|
||||||
- Plain wording, without ALL-CAPS emphasis.
|
- Plain wording, without ALL-CAPS emphasis.
|
||||||
- In code and comments (C, C++, GLSL, CMake, shell, Python, YAML), do not name external projects such as Mesa, Zink or gallium; describe the technique instead. Naming the driver or hardware where a behaviour was observed (llvmpipe, ANGLE, Adreno, Mali) is fine, and so are file, package and extension names that contain these words (`50_mesa.json`, `GL_MESA_*`).
|
- In code and comments (C, C++, GLSL, CMake, shell, Python, YAML), do not name external projects such as Mesa, Zink or gallium; describe the technique instead. Naming the driver or hardware where a behavior was observed (llvmpipe, ANGLE, Adreno, Mali) is fine, and so are file, package and extension names that contain these words (`50_mesa.json`, `GL_MESA_*`).
|
||||||
|
|
||||||
## Code
|
## Code
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ Example:
|
|||||||
5. `MG_Test`, `MG_IntegrationTest` and `MG_Benchmark`.
|
5. `MG_Test`, `MG_IntegrationTest` and `MG_Benchmark`.
|
||||||
- Each backend is isolated. Files under `MG_Backend/DirectGLES/` or `MG_Backend/DirectVulkan/` are included only by the same backend, by the registry files directly in `MG_Backend/`, by the root `.cpp` files and by tests.
|
- Each backend is isolated. Files under `MG_Backend/DirectGLES/` or `MG_Backend/DirectVulkan/` are included only by the same backend, by the registry files directly in `MG_Backend/`, by the root `.cpp` files and by tests.
|
||||||
- Platform-specific APIs stay behind an abstraction, never raw in logic code.
|
- Platform-specific APIs stay behind an abstraction, never raw in logic code.
|
||||||
- A fix that restores intended behaviour ships unconditionally. Add a switch only for a real trade-off.
|
- A fix that restores intended behavior ships unconditionally. Add a switch only for a real trade-off.
|
||||||
- A cache keyed on object identity uses a monotonic lifetime id, never a GL name or a pointer, because both are recycled.
|
- A cache keyed on object identity uses a monotonic lifetime id, never a GL name or a pointer, because both are recycled.
|
||||||
|
|
||||||
## What goes in the repository
|
## What goes in the repository
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ namespace MobileGL {
|
|||||||
// vertex, tessellation control, tessellation evaluation and geometry at 0, and only
|
// vertex, tessellation control, tessellation evaluation and geometry at 0, and only
|
||||||
// fragment (8 in GL, 4 in ES) and compute are guaranteed to have any. Every real ARM
|
// fragment (8 in GL, 4 in ES) and compute are guaranteed to have any. Every real ARM
|
||||||
// GLES driver takes that allowance - a Mali-G925 reports 0 for all four - so a
|
// GLES driver takes that allowance - a Mali-G925 reports 0 for all four - so a
|
||||||
// backend that cannot honour a graphics-stage storage block MUST report 0 here
|
// backend that cannot honor a graphics-stage storage block MUST report 0 here
|
||||||
// rather than a hopeful number. Advertising a non-zero count the driver will refuse
|
// rather than a hopeful number. Advertising a non-zero count the driver will refuse
|
||||||
// does not make the block work; it only moves the failure from an honest
|
// does not make the block work; it only moves the failure from an honest
|
||||||
// "unsupported" at query time to a backend link error the frontend never surfaces,
|
// "unsupported" at query time to a backend link error the frontend never surfaces,
|
||||||
@@ -242,7 +242,7 @@ namespace MobileGL {
|
|||||||
// GL_LAYER_PROVOKING_VERTEX / GL_VIEWPORT_INDEX_PROVOKING_VERTEX: which vertex of a
|
// GL_LAYER_PROVOKING_VERTEX / GL_VIEWPORT_INDEX_PROVOKING_VERTEX: which vertex of a
|
||||||
// primitive supplies gl_Layer and gl_ViewportIndex. GL 4.6 table 23.65 makes
|
// primitive supplies gl_Layer and gl_ViewportIndex. GL 4.6 table 23.65 makes
|
||||||
// GL_UNDEFINED_VERTEX a legal answer for both, and it is the honest default - naming
|
// GL_UNDEFINED_VERTEX a legal answer for both, and it is the honest default - naming
|
||||||
// a convention is a statement about behaviour, so a backend that does not pin one
|
// a convention is a statement about behavior, so a backend that does not pin one
|
||||||
// must not claim it does. DirectGLES fills the layer one from the ES 3.2 query and
|
// must not claim it does. DirectGLES fills the layer one from the ES 3.2 query and
|
||||||
// the viewport one from GL_OES_viewport_array, and leaves UNDEFINED where the
|
// the viewport one from GL_OES_viewport_array, and leaves UNDEFINED where the
|
||||||
// capability is absent: without the viewport array extension only viewport 0 is ever
|
// capability is absent: without the viewport array extension only viewport 0 is ever
|
||||||
@@ -271,7 +271,7 @@ namespace MobileGL {
|
|||||||
// same image and lets an implementation answer GL_FRAMEBUFFER_UNSUPPORTED
|
// same image and lets an implementation answer GL_FRAMEBUFFER_UNSUPPORTED
|
||||||
// otherwise, which is what DirectVulkan (one combined attachment) and the
|
// otherwise, which is what DirectVulkan (one combined attachment) and the
|
||||||
// real ES drivers behind DirectGLES both do. Defaults to true so a backend
|
// real ES drivers behind DirectGLES both do. Defaults to true so a backend
|
||||||
// that never sets it keeps the permissive behaviour.
|
// that never sets it keeps the permissive behavior.
|
||||||
Bool SupportsDistinctDepthStencilAttachments = true;
|
Bool SupportsDistinctDepthStencilAttachments = true;
|
||||||
// Whether attaching a single layer of a 3D or array texture to a framebuffer actually
|
// Whether attaching a single layer of a 3D or array texture to a framebuffer actually
|
||||||
// renders to that layer. DirectGLES hands the layer straight to
|
// renders to that layer. DirectGLES hands the layer straight to
|
||||||
@@ -312,9 +312,9 @@ namespace MobileGL {
|
|||||||
// profile") and the demotion there is mathematically mandatory, always.
|
// profile") and the demotion there is mathematically mandatory, always.
|
||||||
// Defaults to false so a backend that never sets it - and the no-backend case, which
|
// Defaults to false so a backend that never sets it - and the no-backend case, which
|
||||||
// is what standalone shader compiles and the unit tests run under - keeps the
|
// is what standalone shader compiles and the unit tests run under - keeps the
|
||||||
// demotion, which is the behaviour that works everywhere.
|
// demotion, which is the behavior that works everywhere.
|
||||||
Bool SupportsShaderFloat64 = false;
|
Bool SupportsShaderFloat64 = false;
|
||||||
// Whether glVertexAttribLFormat / glVertexArrayAttribLFormat can be honoured, i.e.
|
// Whether glVertexAttribLFormat / glVertexArrayAttribLFormat can be honored, i.e.
|
||||||
// whether a 64-bit vertex attribute can actually reach a shader unconverted. Detected,
|
// whether a 64-bit vertex attribute can actually reach a shader unconverted. Detected,
|
||||||
// never assumed: DirectVulkan needs VkPhysicalDeviceFeatures::shaderFloat64 (the
|
// never assumed: DirectVulkan needs VkPhysicalDeviceFeatures::shaderFloat64 (the
|
||||||
// attribute travels as its 32-bit word pair, so no VK_FORMAT_R64* is required, but the
|
// attribute travels as its 32-bit word pair, so no VK_FORMAT_R64* is required, but the
|
||||||
@@ -382,7 +382,7 @@ namespace MobileGL {
|
|||||||
Bool FragmentShadingRateAttachmentWithDefaultFramebuffer = false;
|
Bool FragmentShadingRateAttachmentWithDefaultFramebuffer = false;
|
||||||
// What glGetFragmentShadingRatesEXT answers, one mask per sample count 1, 2, 4 .. 64
|
// What glGetFragmentShadingRatesEXT answers, one mask per sample count 1, 2, 4 .. 64
|
||||||
// (index = log2(samples)): bit (log2(w) << 2 | log2(h)) is set when that rate is
|
// (index = log2(samples)): bit (log2(w) << 2 | log2(h)) is set when that rate is
|
||||||
// honoured exactly at that sample count, i.e. gl_ShadingRateEXT reads it back
|
// honored exactly at that sample count, i.e. gl_ShadingRateEXT reads it back
|
||||||
// unclamped. Zero masks mean no rate at all, which is what a sample count the device
|
// unclamped. Zero masks mean no rate at all, which is what a sample count the device
|
||||||
// cannot shade coarsely answers.
|
// cannot shade coarsely answers.
|
||||||
Uint16 FragmentShadingRateMasks[7] = {};
|
Uint16 FragmentShadingRateMasks[7] = {};
|
||||||
|
|||||||
+9
-9
@@ -164,7 +164,7 @@ namespace MobileGL::MG_Config {
|
|||||||
// surface's minimum (the frames-in-flight count still raises the request when it is
|
// surface's minimum (the frames-in-flight count still raises the request when it is
|
||||||
// larger), clamped to the surface's maximum. With more images, the one the display has
|
// larger), clamped to the surface's maximum. With more images, the one the display has
|
||||||
// just released is reused later, by when its release has usually signaled, so fewer
|
// just released is reused later, by when its release has usually signaled, so fewer
|
||||||
// frames start their window pass behind it. Each image costs a full-size colour buffer
|
// frames start their window pass behind it. Each image costs a full-size color buffer
|
||||||
// plus the default framebuffer's depth/stencil buffer of the same size.
|
// plus the default framebuffer's depth/stencil buffer of the same size.
|
||||||
Uint32 MagmaExtraSwapchainImages = 0;
|
Uint32 MagmaExtraSwapchainImages = 0;
|
||||||
// MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER: GL draws and dispatches Magma records into
|
// MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER: GL draws and dispatches Magma records into
|
||||||
@@ -316,10 +316,10 @@ namespace MobileGL::MG_Config {
|
|||||||
// keeps the built-in default (MG_Util::Async::kAsyncShaderCompileDefault); falsy
|
// keeps the built-in default (MG_Util::Async::kAsyncShaderCompileDefault); falsy
|
||||||
// forces every glCompileShader/glLinkProgram to run synchronously on the calling
|
// forces every glCompileShader/glLinkProgram to run synchronously on the calling
|
||||||
// thread AND withdraws GL_KHR_parallel_shader_compile, so the single switch reverts
|
// thread AND withdraws GL_KHR_parallel_shader_compile, so the single switch reverts
|
||||||
// both the threading and the application-visible behaviour change.
|
// both the threading and the application-visible behavior change.
|
||||||
QuirkOverride AsyncShaderCompile = QuirkOverride::Auto;
|
QuirkOverride AsyncShaderCompile = QuirkOverride::Auto;
|
||||||
// MOBILEGL_ASYNC_SHADER_COMPILE_THREADS: shader-compile worker count. 0 (unset) means
|
// MOBILEGL_ASYNC_SHADER_COMPILE_THREADS: shader-compile worker count. 0 (unset) means
|
||||||
// auto, which is min(4, big cores); an explicit value is honoured as given.
|
// auto, which is min(4, big cores); an explicit value is honored as given.
|
||||||
Uint32 AsyncShaderCompileThreads = 0;
|
Uint32 AsyncShaderCompileThreads = 0;
|
||||||
// MOBILEGL_DISABLE_SHADER_PREWARM: skip the glslang built-in table prewarm in
|
// MOBILEGL_DISABLE_SHADER_PREWARM: skip the glslang built-in table prewarm in
|
||||||
// Initialize(), which moves ~20-100 ms of table building from the first shader compiles
|
// Initialize(), which moves ~20-100 ms of table building from the first shader compiles
|
||||||
@@ -356,7 +356,7 @@ namespace MobileGL::MG_Config {
|
|||||||
// extension only ever gave the SHADER a compilable name: MobileGL has never
|
// extension only ever gave the SHADER a compilable name: MobileGL has never
|
||||||
// programmed a driver's INDEXED viewport state (SyncRenderState pushes index 0
|
// programmed a driver's INDEXED viewport state (SyncRenderState pushes index 0
|
||||||
// and nothing else), so on an extension-capable driver every index rasterized as
|
// and nothing else), so on an extension-capable driver every index rasterized as
|
||||||
// index 0 exactly as it did without one. ForceOff returns to that behaviour -
|
// index 0 exactly as it did without one. ForceOff returns to that behavior -
|
||||||
// the pre-emulation path, extension passthrough where it exists and
|
// the pre-emulation path, extension passthrough where it exists and
|
||||||
// LowerViewportIndexPass' demote-to-a-plain-global where it does not - and is
|
// LowerViewportIndexPass' demote-to-a-plain-global where it does not - and is
|
||||||
// the negative control the emulation is measured against.
|
// the negative control the emulation is measured against.
|
||||||
@@ -420,7 +420,7 @@ namespace MobileGL::MG_Config {
|
|||||||
// MOBILEGL_PIPE_PUSH: per-subsystem bitmask selecting which state the frontend
|
// MOBILEGL_PIPE_PUSH: per-subsystem bitmask selecting which state the frontend
|
||||||
// PUSHES over MGPipe instead of leaving the backend to pull it out of GLContext.
|
// PUSHES over MGPipe instead of leaving the backend to pull it out of GLContext.
|
||||||
// 0 - the only shipped value until the migration lands - is "pull everything",
|
// 0 - the only shipped value until the migration lands - is "pull everything",
|
||||||
// i.e. exactly today's behaviour, and is the default of a PULL build, where the
|
// i.e. exactly today's behavior, and is the default of a PULL build, where the
|
||||||
// knob is meaningless anyway. A PUSH build defaults to every subsystem migrated so
|
// knob is meaningless anyway. A PUSH build defaults to every subsystem migrated so
|
||||||
// far (MG_Pipe::kMGPipeSubsystemsMigratedAtP5e = 0x3fff), so MOBILEGL_PIPE_PUSH=0 in
|
// far (MG_Pipe::kMGPipeSubsystemsMigratedAtP5e = 0x3fff), so MOBILEGL_PIPE_PUSH=0 in
|
||||||
// the environment is the all-pull control and 0x1fff (kMGPipeSubsystemsMigratedAtP4a)
|
// the environment is the all-pull control and 0x1fff (kMGPipeSubsystemsMigratedAtP4a)
|
||||||
@@ -447,7 +447,7 @@ namespace MobileGL::MG_Config {
|
|||||||
// (every MGPBufferRange::Res names a Buffer handle; P5e)
|
// (every MGPBufferRange::Res names a Buffer handle; P5e)
|
||||||
// A dependency that is not met is REFUSED with one ERROR naming both bits and the
|
// A dependency that is not met is REFUSED with one ERROR naming both bits and the
|
||||||
// family runs its legacy arm; it is never half-run.
|
// family runs its legacy arm; it is never half-run.
|
||||||
// 1<<63 NOT a subsystem, a BEHAVIOUR: turn OFF client-side content addressing of
|
// 1<<63 NOT a subsystem, a BEHAVIOR: turn OFF client-side content addressing of
|
||||||
// CSOs, so every pipeline-version change mints a fresh CSO and the map is
|
// CSOs, so every pipeline-version change mints a fresh CSO and the map is
|
||||||
// never probed. The negative control the CSO design is measured against.
|
// never probed. The negative control the CSO design is measured against.
|
||||||
// P13 W3b (ID-P13-3): bits 0-13 are FIXED ON. Their pre-handle arms are gone, so a mask
|
// P13 W3b (ID-P13-3): bits 0-13 are FIXED ON. Their pre-handle arms are gone, so a mask
|
||||||
@@ -489,7 +489,7 @@ namespace MobileGL::MG_Config {
|
|||||||
extern FeaturesTable Features;
|
extern FeaturesTable Features;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
// P5: the transport selector and the MOBILEGL_IPC_* family (ARCHITECTURE.md 16, 附 A)
|
// P5: the transport selector and the MOBILEGL_IPC_* family (ARCHITECTURE.md 16, appendix A)
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>.
|
// MOBILEGL_TRANSPORT = monolith | inproc | spawn | unix:<path> | pipe:<name>.
|
||||||
@@ -573,7 +573,7 @@ namespace MobileGL::MG_Config {
|
|||||||
|
|
||||||
// The MOBILEGL_IPC_* family. A separate table rather than more FeaturesTable members,
|
// The MOBILEGL_IPC_* family. A separate table rather than more FeaturesTable members,
|
||||||
// for the G1 reason above and because every field here is meaningless without the
|
// for the G1 reason above and because every field here is meaningless without the
|
||||||
// transport: a build that cannot reach the MG_Remote code cannot honour one of them.
|
// transport: a build that cannot reach the MG_Remote code cannot honor one of them.
|
||||||
//
|
//
|
||||||
// P5 lands exactly the knobs P5's own packages read. A later phase's knob is added HERE,
|
// P5 lands exactly the knobs P5's own packages read. A later phase's knob is added HERE,
|
||||||
// through the integrator, and not invented at its call site - ARCHITECTURE.md appendix A holds
|
// through the integrator, and not invented at its call site - ARCHITECTURE.md appendix A holds
|
||||||
@@ -753,7 +753,7 @@ namespace MobileGL::MG_Config {
|
|||||||
// own) and no SetWindowHandle, and take the surface's real geometry back from the server.
|
// own) and no SetWindowHandle, and take the surface's real geometry back from the server.
|
||||||
// Meaningful only when this client talks to a remote server (MOBILEGL_TRANSPORT=spawn, the
|
// Meaningful only when this client talks to a remote server (MOBILEGL_TRANSPORT=spawn, the
|
||||||
// fork or tcp:// control); under monolith / inproc it is parsed, logged as ignored, and
|
// fork or tcp:// control); under monolith / inproc it is parsed, logged as ignored, and
|
||||||
// changes nothing. `offscreen` (the default) is today's behaviour byte for byte.
|
// changes nothing. `offscreen` (the default) is today's behavior byte for byte.
|
||||||
// Pbuffers stay pbuffers in both modes (D4: one mode per session, decided by the first).
|
// Pbuffers stay pbuffers in both modes (D4: one mode per session, decided by the first).
|
||||||
IpcSurface Surface = IpcSurface::Offscreen;
|
IpcSurface Surface = IpcSurface::Offscreen;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
"ring to an apply thread");
|
"ring to an apply thread");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The three P6 forms. Recognised precisely, so the diagnostic can say "rejected"
|
// The three P6 forms. Recognized precisely, so the diagnostic can say "rejected"
|
||||||
// rather than "unknown", which are different bugs on the operator's side.
|
// rather than "unknown", which are different bugs on the operator's side.
|
||||||
// P6 `sm`/`cp`: spawn is IMPLEMENTED. It launches a server process on a
|
// P6 `sm`/`cp`: spawn is IMPLEMENTED. It launches a server process on a
|
||||||
// rendezvous of its own and connects to it - the two processes are
|
// rendezvous of its own and connects to it - the two processes are
|
||||||
@@ -575,7 +575,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
QueryEnvVariable("MOBILEGL_IPC_CONTROL", ipc.Control, "fork");
|
QueryEnvVariable("MOBILEGL_IPC_CONTROL", ipc.Control, "fork");
|
||||||
QueryEnvVariable("MOBILEGL_IPC_DATA", ipc.Data, "auto");
|
QueryEnvVariable("MOBILEGL_IPC_DATA", ipc.Data, "auto");
|
||||||
// Both ring floors are 1 MiB, not 0: a ring caps ONE record at half its size, and
|
// Both ring floors are 1 MiB, not 0: a ring caps ONE record at half its size, and
|
||||||
// the catalogue's largest fixed payload (MGPFramebufferState, 304 bytes) plus a
|
// the catalog's largest fixed payload (MGPFramebufferState, 304 bytes) plus a
|
||||||
// create_shader_state archive already needs far more than a toy ring. The ceilings
|
// create_shader_state archive already needs far more than a toy ring. The ceilings
|
||||||
// are sanity, not policy.
|
// are sanity, not policy.
|
||||||
ipc.RingMb = QueryEnvUint32("MOBILEGL_IPC_RING_MB", 8, 1, 1024);
|
ipc.RingMb = QueryEnvUint32("MOBILEGL_IPC_RING_MB", 8, 1, 1024);
|
||||||
@@ -703,7 +703,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
const Bool serverProcess = role != nullptr && std::strcmp(role, "server") == 0;
|
const Bool serverProcess = role != nullptr && std::strcmp(role, "server") == 0;
|
||||||
if (ipc.Surface == MG_Config::IpcSurface::Server && !serverProcess &&
|
if (ipc.Surface == MG_Config::IpcSurface::Server && !serverProcess &&
|
||||||
MG_Config::Transport != MG_Config::TransportMode::Spawn) {
|
MG_Config::Transport != MG_Config::TransportMode::Spawn) {
|
||||||
// Said, not silently honoured: there is no remote server here to own a window.
|
// Said, not silently honored: there is no remote server here to own a window.
|
||||||
MGLOG_W("Config: MOBILEGL_IPC_SURFACE=server is IGNORED - it asks a remote server "
|
MGLOG_W("Config: MOBILEGL_IPC_SURFACE=server is IGNORED - it asks a remote server "
|
||||||
"(MOBILEGL_TRANSPORT=spawn, a fork or tcp:// control) to own the window surface, "
|
"(MOBILEGL_TRANSPORT=spawn, a fork or tcp:// control) to own the window surface, "
|
||||||
"and this run has none. Window surfaces stay the client's own");
|
"and this run has none. Window surfaces stay the client's own");
|
||||||
@@ -711,7 +711,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) return;
|
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) return;
|
||||||
// One line, on the arm where these numbers decide behaviour, because every one of
|
// One line, on the arm where these numbers decide behavior, because every one of
|
||||||
// them is a number a bug report has to quote.
|
// them is a number a bug report has to quote.
|
||||||
// CREATE-WINDOW IS IN THIS LINE BECAUSE A RUN HAS TO SAY WHICH WINDOW IT USED. It was
|
// CREATE-WINDOW IS IN THIS LINE BECAUSE A RUN HAS TO SAY WHICH WINDOW IT USED. It was
|
||||||
// missing while the value was a number nobody varied, and the moment it became one that
|
// missing while the value was a number nobody varied, and the moment it became one that
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
void (*BeginTransformFeedback)(GLenum primitiveMode);
|
void (*BeginTransformFeedback)(GLenum primitiveMode);
|
||||||
void (*EndTransformFeedback)();
|
void (*EndTransformFeedback)();
|
||||||
// ARB_transform_feedback2. A backend that leaves these null keeps the single
|
// ARB_transform_feedback2. A backend that leaves these null keeps the single
|
||||||
// implicit capture span the frontend has always modelled; the frontend state
|
// implicit capture span the frontend has always modeled; the frontend state
|
||||||
// (paused flag, per-object bindings) is tracked either way.
|
// (paused flag, per-object bindings) is tracked either way.
|
||||||
void (*PauseTransformFeedback)();
|
void (*PauseTransformFeedback)();
|
||||||
void (*ResumeTransformFeedback)();
|
void (*ResumeTransformFeedback)();
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// The same for a YUV fourcc, whose planes and hints `layout` gives. A YUV buffer the
|
// The same for a YUV fourcc, whose planes and hints `layout` gives. A YUV buffer the
|
||||||
// server did not export is taken too (its labelled CPU-copy fallback).
|
// server did not export is taken too (its labeled CPU-copy fallback).
|
||||||
virtual Bool ImportSharedImagePlanes(int fd, Uint32 width, Uint32 height, Uint32 fourcc,
|
virtual Bool ImportSharedImagePlanes(int fd, Uint32 width, Uint32 height, Uint32 fourcc,
|
||||||
const SharedImageImportLayout& layout, Uint64* outId) {
|
const SharedImageImportLayout& layout, Uint64* outId) {
|
||||||
(void)fd, (void)width, (void)height, (void)fourcc, (void)layout, (void)outId;
|
(void)fd, (void)width, (void)height, (void)fourcc, (void)layout, (void)outId;
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
reasons.push_back("GL_DEPTH_COMPONENT32 native probe failed on OpenGL ES");
|
reasons.push_back("GL_DEPTH_COMPONENT32 native probe failed on OpenGL ES");
|
||||||
}
|
}
|
||||||
if (options & PixelFormatNormalizeOptionBit::NoThreeChannelRenderTarget) {
|
if (options & PixelFormatNormalizeOptionBit::NoThreeChannelRenderTarget) {
|
||||||
reasons.push_back("no colour-renderable three-channel format on OpenGL ES");
|
reasons.push_back("no color-renderable three-channel format on OpenGL ES");
|
||||||
}
|
}
|
||||||
// A format is either 8- or 16-bit signed normalized, so at most one of the two ever
|
// A format is either 8- or 16-bit signed normalized, so at most one of the two ever
|
||||||
// survives GetApplicablePixelFormatNormalizeOptions and the reason is not duplicated.
|
// survives GetApplicablePixelFormatNormalizeOptions and the reason is not duplicated.
|
||||||
@@ -369,7 +369,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// did - is not merely untidy: the two texture pnames are ES 3.1 state, so on an ES 3.0
|
// did - is not merely untidy: the two texture pnames are ES 3.1 state, so on an ES 3.0
|
||||||
// context the loader's rejected-probe clamp leaves them at 1 (see the multisample clamps
|
// context the loader's rejected-probe clamp leaves them at 1 (see the multisample clamps
|
||||||
// in the GLES loader) and the walk below would never run past one sample, recording {1}
|
// in the GLES loader) and the walk below would never run past one sample, recording {1}
|
||||||
// for EVERY colour format while GL_MAX_SAMPLES - ES 3.0 core, so genuinely answered -
|
// for EVERY color format while GL_MAX_SAMPLES - ES 3.0 core, so genuinely answered -
|
||||||
// reports 4. Once the frontend validates against this list, that would reject every
|
// reports 4. Once the frontend validates against this list, that would reject every
|
||||||
// multisample renderbuffer on such a context.
|
// multisample renderbuffer on such a context.
|
||||||
Int GetGLESRenderbufferFormatMaxSamples(const MG_External::GLESCapabilities& capabilities, GLenum imageFormat) {
|
Int GetGLESRenderbufferFormatMaxSamples(const MG_External::GLESCapabilities& capabilities, GLenum imageFormat) {
|
||||||
@@ -707,7 +707,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTextureTargetCount; ++targetIndex) {
|
for (SizeT targetIndex = 0; targetIndex < kFormatCapabilityTextureTargetCount; ++targetIndex) {
|
||||||
const auto target = static_cast<TextureTarget>(targetIndex);
|
const auto target = static_cast<TextureTarget>(targetIndex);
|
||||||
// Colour-attachable targets need a colour-renderable fallback; the ordinary
|
// Color-attachable targets need a color-renderable fallback; the ordinary
|
||||||
// fallback for a three-channel format is another three-channel one, which ES
|
// fallback for a three-channel format is another three-channel one, which ES
|
||||||
// accepts as a texture but never as an attachment. Recompute the fallback per
|
// accepts as a texture but never as an attachment. Recompute the fallback per
|
||||||
// target so those formats get widened where the target demands it.
|
// target so those formats get widened where the target demands it.
|
||||||
@@ -814,7 +814,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
const SizeT renderbufferTargetIndex = GetRenderbufferFormatCapabilityTargetIndex();
|
const SizeT renderbufferTargetIndex = GetRenderbufferFormatCapabilityTargetIndex();
|
||||||
// A renderbuffer exists only to be attached, so it needs the same three-channel
|
// A renderbuffer exists only to be attached, so it needs the same three-channel
|
||||||
// widening the colour-attachable texture targets get - and on the same terms: the
|
// widening the color-attachable texture targets get - and on the same terms: the
|
||||||
// native storage is probed first, so a driver that renders to it keeps it.
|
// native storage is probed first, so a driver that renders to it keeps it.
|
||||||
const Flags<PixelFormatNormalizeOptionBit> renderbufferOptions =
|
const Flags<PixelFormatNormalizeOptionBit> renderbufferOptions =
|
||||||
TextureImpl::GetRenderTargetNormalizeOptions(capabilities, renderbufferTargetIndex);
|
TextureImpl::GetRenderTargetNormalizeOptions(capabilities, renderbufferTargetIndex);
|
||||||
@@ -1053,7 +1053,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// built).
|
// built).
|
||||||
UpdateAdvertisedCapabilityExtensions(m_GLESCapabilities);
|
UpdateAdvertisedCapabilityExtensions(m_GLESCapabilities);
|
||||||
UpdateDynamicBackendParameters();
|
UpdateDynamicBackendParameters();
|
||||||
// The colour-attachment cap the framebuffer family checks is known from here on.
|
// The color-attachment cap the framebuffer family checks is known from here on.
|
||||||
DirectGLES::ResolveRecordArmFamilies();
|
DirectGLES::ResolveRecordArmFamilies();
|
||||||
PopulateFormatCapabilities(m_GLESFunctions, m_GLESCapabilities, MutableFormatCapabilities());
|
PopulateFormatCapabilities(m_GLESFunctions, m_GLESCapabilities, MutableFormatCapabilities());
|
||||||
PrintFormatCapabilities(GetFormatCapabilities());
|
PrintFormatCapabilities(GetFormatCapabilities());
|
||||||
@@ -1540,7 +1540,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
E_GL_ARB_texture_rg,
|
E_GL_ARB_texture_rg,
|
||||||
// GL_DEPTH_COMPONENT32F and GL_DEPTH32F_STENCIL8.
|
// GL_DEPTH_COMPONENT32F and GL_DEPTH32F_STENCIL8.
|
||||||
E_GL_ARB_depth_buffer_float,
|
E_GL_ARB_depth_buffer_float,
|
||||||
// The floating-point colour formats. Unlike the rest of this block this string DOES
|
// The floating-point color formats. Unlike the rest of this block this string DOES
|
||||||
// gate CTS cases - KHR-GL4*.internalformat.texture2d.*{16f,32f} is keyed on it with no
|
// gate CTS cases - KHR-GL4*.internalformat.texture2d.*{16f,32f} is keyed on it with no
|
||||||
// core-version fallback, so eight cases per version list were NotSupported on formats
|
// core-version fallback, so eight cases per version list were NotSupported on formats
|
||||||
// the backend has always had.
|
// the backend has always had.
|
||||||
@@ -1557,7 +1557,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// - multiple capture buffers per stream, gl_SkipComponents / gl_NextBuffer, the
|
// - multiple capture buffers per stream, gl_SkipComponents / gl_NextBuffer, the
|
||||||
// indexed queries and glDrawTransformFeedbackStream (4.0);
|
// indexed queries and glDrawTransformFeedbackStream (4.0);
|
||||||
E_GL_ARB_transform_feedback3,
|
E_GL_ARB_transform_feedback3,
|
||||||
// - GL_RGB10_A2UI (3.3), GL_RGB9_E5 (3.0) and the integer colour formats (3.0);
|
// - GL_RGB10_A2UI (3.3), GL_RGB9_E5 (3.0) and the integer color formats (3.0);
|
||||||
E_GL_ARB_texture_rgb10_a2ui, E_GL_EXT_texture_shared_exponent, E_GL_EXT_texture_integer,
|
E_GL_ARB_texture_rgb10_a2ui, E_GL_EXT_texture_shared_exponent, E_GL_EXT_texture_integer,
|
||||||
// - the eleven pipeline-statistics query targets (4.6). Accepted by glBeginQuery and
|
// - the eleven pipeline-statistics query targets (4.6). Accepted by glBeginQuery and
|
||||||
// answered with GL_QUERY_COUNTER_BITS = 0, the spec's own "this counter is not
|
// answered with GL_QUERY_COUNTER_BITS = 0, the spec's own "this counter is not
|
||||||
@@ -1609,7 +1609,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// recorded trace can never cover: Iris and Sodium change their SUBMISSION SCHEDULE
|
// recorded trace can never cover: Iris and Sodium change their SUBMISSION SCHEDULE
|
||||||
// the moment they see it - they enqueue whole pipeline batches and poll
|
// the moment they see it - they enqueue whole pipeline batches and poll
|
||||||
// GL_COMPLETION_STATUS_KHR instead of compiling one program at a time - so
|
// GL_COMPLETION_STATUS_KHR instead of compiling one program at a time - so
|
||||||
// MOBILEGL_ASYNC_SHADER_COMPILE=0 has to withdraw the application-visible behaviour
|
// MOBILEGL_ASYNC_SHADER_COMPILE=0 has to withdraw the application-visible behavior
|
||||||
// change as well as the threading, or the kill switch would only be half a switch.
|
// change as well as the threading, or the kill switch would only be half a switch.
|
||||||
if (MG_Util::Async::AsyncShaderCompileEnabled()) {
|
if (MG_Util::Async::AsyncShaderCompileEnabled()) {
|
||||||
extensions.push_back(E_GL_KHR_parallel_shader_compile);
|
extensions.push_back(E_GL_KHR_parallel_shader_compile);
|
||||||
@@ -1619,7 +1619,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// reaches this backend - so an application that simply uses doubles needs nothing
|
// reaches this backend - so an application that simply uses doubles needs nothing
|
||||||
// advertised. What the extension additionally promises is 64-bit PRECISION, which no
|
// advertised. What the extension additionally promises is 64-bit PRECISION, which no
|
||||||
// mobile GPU has and the narrowing cannot fake, so advertising it by default would
|
// mobile GPU has and the narrowing cannot fake, so advertising it by default would
|
||||||
// make an application that checks the string take a path MobileGL cannot honour.
|
// make an application that checks the string take a path MobileGL cannot honor.
|
||||||
if (MG_Config::Features.AdvertiseFp64) {
|
if (MG_Config::Features.AdvertiseFp64) {
|
||||||
extensions.push_back(E_GL_ARB_gpu_shader_fp64);
|
extensions.push_back(E_GL_ARB_gpu_shader_fp64);
|
||||||
}
|
}
|
||||||
@@ -1650,7 +1650,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// DEPTH_STENCIL_TEXTURE_MODE = STENCIL_INDEX and through a view with DEPTH_COMPONENT, in
|
// DEPTH_STENCIL_TEXTURE_MODE = STENCIL_INDEX and through a view with DEPTH_COMPONENT, in
|
||||||
// a single shading pass). A copy-based fallback satisfies neither half, and fails
|
// a single shading pass). A copy-based fallback satisfies neither half, and fails
|
||||||
// silently; withholding the string and answering glTextureView with INVALID_OPERATION is
|
// silently; withholding the string and answering glTextureView with INVALID_OPERATION is
|
||||||
// the only behaviour that cannot be mistaken for success.
|
// the only behavior that cannot be mistaken for success.
|
||||||
//
|
//
|
||||||
// The host extension is necessary and NOT sufficient, which is why this second gate
|
// The host extension is necessary and NOT sufficient, which is why this second gate
|
||||||
// exists. Adreno 830 has EXT_texture_view, and on it the whole functional half of
|
// exists. Adreno 830 has EXT_texture_view, and on it the whole functional half of
|
||||||
@@ -1891,7 +1891,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
// (MaxShaderStorageBufferBindings is assigned above, before the per-stage clamp reads it.)
|
// (MaxShaderStorageBufferBindings is assigned above, before the per-stage clamp reads it.)
|
||||||
// This is the number glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE) hands the application, and
|
// This is the number glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE) hands the application, and
|
||||||
// on a host without buffer textures it is knowingly a floor MobileGL cannot honour rather
|
// on a host without buffer textures it is knowingly a floor MobileGL cannot honor rather
|
||||||
// than a driver answer (m_GLESCapabilities.MaxTextureBufferSizeIsDriverReported says
|
// than a driver answer (m_GLESCapabilities.MaxTextureBufferSizeIsDriverReported says
|
||||||
// which). Reporting 0 instead was considered and rejected: MobileGL advertises an OpenGL
|
// which). Reporting 0 instead was considered and rejected: MobileGL advertises an OpenGL
|
||||||
// 4.x context, where buffer textures are core and the limit has a spec minimum of 65536,
|
// 4.x context, where buffer textures are core and the limit has a spec minimum of 65536,
|
||||||
@@ -2007,7 +2007,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// for gl_ViewportIndex on every driver without GL_OES_viewport_array - which is both test
|
// for gl_ViewportIndex on every driver without GL_OES_viewport_array - which is both test
|
||||||
// devices. That is not a shortfall being hidden: without the extension only viewport 0 is
|
// devices. That is not a shortfall being hidden: without the extension only viewport 0 is
|
||||||
// ever rasterized, so no vertex "selects" a viewport index and naming a convention would
|
// ever rasterized, so no vertex "selects" a viewport index and naming a convention would
|
||||||
// describe behaviour this backend does not implement.
|
// describe behavior this backend does not implement.
|
||||||
m_dynamicParameters.LayerProvokingVertex = m_GLESCapabilities.LayerProvokingVertex;
|
m_dynamicParameters.LayerProvokingVertex = m_GLESCapabilities.LayerProvokingVertex;
|
||||||
m_dynamicParameters.ViewportIndexProvokingVertex = m_GLESCapabilities.ViewportIndexProvokingVertex;
|
m_dynamicParameters.ViewportIndexProvokingVertex = m_GLESCapabilities.ViewportIndexProvokingVertex;
|
||||||
// GL_EXT_fragment_shading_rate is a straight pass-through: the pipeline rate and the
|
// GL_EXT_fragment_shading_rate is a straight pass-through: the pipeline rate and the
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// deliberate and it is not this phase's to change: ARCHITECTURE.md assigns the two
|
// deliberate and it is not this phase's to change: ARCHITECTURE.md assigns the two
|
||||||
// backend-specific post-processings of the resolved sampler set - this one and Magma's
|
// backend-specific post-processings of the resolved sampler set - this one and Magma's
|
||||||
// feedback-loop detection - to the server, acting ON the already-resolved set, and the
|
// feedback-loop detection - to the server, acting ON the already-resolved set, and the
|
||||||
// ROADMAP puts "raw-depth-fetch sampler 原生化" in P3b/P4b beside Magma's placeholder
|
// ROADMAP puts "native raw-depth-fetch sampler" in P3b/P4b beside Magma's placeholder
|
||||||
// textures. What P4a changes is only what the substitution READS: the resolved view's
|
// textures. What P4a changes is only what the substitution READS: the resolved view's
|
||||||
// format answers IsDepthFormatInternalFormat and the sampler CSO record's parameters
|
// format answers IsDepthFormatInternalFormat and the sampler CSO record's parameters
|
||||||
// answer compareMode / minFilter / mipmapMode / magFilter.
|
// answer compareMode / minFilter / mipmapMode / magFilter.
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// glTexBuffer / glTexBufferRange through whichever spelling this driver's buffer-texture
|
// glTexBuffer / glTexBufferRange through whichever spelling this driver's buffer-texture
|
||||||
// support actually ships: the unsuffixed names are ES 3.2 core, while an EXT/OES driver
|
// support actually ships: the unsuffixed names are ES 3.2 core, while an EXT/OES driver
|
||||||
// exports glTexBuffer{,Range}EXT / OES. Callers must have checked
|
// exports glTexBuffer{,Range}EXT / OES. Callers must have checked
|
||||||
// AreBufferTexturesSupported() first. CallTexBufferRange reports whether it could honour
|
// AreBufferTexturesSupported() first. CallTexBufferRange reports whether it could honor
|
||||||
// the range - no tier is required to expose the range form, and the whole-buffer form is
|
// the range - no tier is required to expose the range form, and the whole-buffer form is
|
||||||
// the documented fallback.
|
// the documented fallback.
|
||||||
void CallTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer);
|
void CallTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer);
|
||||||
@@ -448,7 +448,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// hold" query and no way to ask a context for its share group, so a case that must tell "the
|
// hold" query and no way to ask a context for its share group, so a case that must tell "the
|
||||||
// same native context still serves" from "a fresh one was built", or a sharing pair from two
|
// same native context still serves" from "a fresh one was built", or a sharing pair from two
|
||||||
// unrelated contexts, reads it here. These are pure reads plus one key override; neither is on
|
// unrelated contexts, reads it here. These are pure reads plus one key override; neither is on
|
||||||
// a production path and neither changes behaviour.
|
// a production path and neither changes behavior.
|
||||||
EGLContext NativeContextHandleFor(Uint64 sessionKey, Uint64 contextToken);
|
EGLContext NativeContextHandleFor(Uint64 sessionKey, Uint64 contextToken);
|
||||||
// Overrides the key the calling thread resolves to, for the life of the call. The backend's
|
// Overrides the key the calling thread resolves to, for the life of the call. The backend's
|
||||||
// ordinary answer comes from the server layer's probe; this is how a case drives exactly the
|
// ordinary answer comes from the server layer's probe; this is how a case drives exactly the
|
||||||
@@ -484,8 +484,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Pushes the frontend's render-state block to the ES driver, diffed against what was
|
// Pushes the frontend's render-state block to the ES driver, diffed against what was
|
||||||
// last pushed.
|
// last pushed.
|
||||||
//
|
//
|
||||||
// `forColorClear` names the CALLER, and the only thing it changes is the colour write
|
// `forColorClear` names the CALLER, and the only thing it changes is the color write
|
||||||
// mask handed to the driver. A draw into a colour attachment the backend widened from
|
// mask handed to the driver. A draw into a color attachment the backend widened from
|
||||||
// three channels to four gets that buffer's alpha channel masked OFF, so nothing can
|
// three channels to four gets that buffer's alpha channel masked OFF, so nothing can
|
||||||
// move the stored alpha away from the 1.0 the application's three-channel format
|
// move the stored alpha away from the 1.0 the application's three-channel format
|
||||||
// implies (see FramebufferImpl::g_alphaWidenedDrawBufferMask). A CLEAR is how that 1.0
|
// implies (see FramebufferImpl::g_alphaWidenedDrawBufferMask). A CLEAR is how that 1.0
|
||||||
@@ -494,7 +494,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// followed by a draw re-pushes the mask instead of early-outing on an unchanged
|
// followed by a draw re-pushes the mask instead of early-outing on an unchanged
|
||||||
// frontend version.
|
// frontend version.
|
||||||
//
|
//
|
||||||
// The application's own colour mask is never modified: glGet(GL_COLOR_WRITEMASK)
|
// The application's own color mask is never modified: glGet(GL_COLOR_WRITEMASK)
|
||||||
// answers from the frontend state, which this function only reads.
|
// answers from the frontend state, which this function only reads.
|
||||||
void SyncRenderState(Bool forColorClear = false);
|
void SyncRenderState(Bool forColorClear = false);
|
||||||
void InvalidateSyncedRenderState();
|
void InvalidateSyncedRenderState();
|
||||||
|
|||||||
@@ -636,7 +636,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// BOUNDS-CHECKED, exactly as ProgramObject::GetAttribType is not: the frontend's
|
// BOUNDS-CHECKED, exactly as ProgramObject::GetAttribType is not: the frontend's
|
||||||
// form indexes attribTypes raw because the mask it walked came off the same
|
// form indexes attribTypes raw because the mask it walked came off the same
|
||||||
// artefacts instance, and here the two vectors arrived over a wire. A short tail
|
// artifacts instance, and here the two vectors arrived over a wire. A short tail
|
||||||
// is an archive whose halves disagree; 0 classifies as Unsupported and says so
|
// is an archive whose halves disagree; 0 classifies as Unsupported and says so
|
||||||
// below rather than reading past the end.
|
// below rather than reading past the end.
|
||||||
const GLenum attribType = location < link.attribTypes.size() ? link.attribTypes[location] : 0;
|
const GLenum attribType = location < link.attribTypes.size() ? link.attribTypes[location] : 0;
|
||||||
@@ -686,7 +686,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// declined to run it.
|
// declined to run it.
|
||||||
//
|
//
|
||||||
// P4a e3 (D-G4) leaves BOTH properties of this gate exactly as they are, and says so
|
// P4a e3 (D-G4) leaves BOTH properties of this gate exactly as they are, and says so
|
||||||
// because they are the kind of thing a later optimisation deletes:
|
// because they are the kind of thing a later optimization deletes:
|
||||||
//
|
//
|
||||||
// 1. the g_imageUnitHighWaterMark == 0 early-out is what makes every Minecraft draw
|
// 1. the g_imageUnitHighWaterMark == 0 early-out is what makes every Minecraft draw
|
||||||
// pay one integer test, and it is asked BEFORE anything reads a record;
|
// pay one integer test, and it is asked BEFORE anything reads a record;
|
||||||
@@ -1710,7 +1710,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// The last sample a usampler2DMS fetch may name, from the texture
|
// The last sample a usampler2DMS fetch may name, from the texture
|
||||||
// actually bound: a stencil texture's real count is not an integer
|
// actually bound: a stencil texture's real count is not an integer
|
||||||
// colour texture's. Keyed like the bias above - a texture's storage or
|
// color texture's. Keyed like the bias above - a texture's storage or
|
||||||
// a unit's binding moving is what invalidates this pass's memo.
|
// a unit's binding moving is what invalidates this pass's memo.
|
||||||
if (samplerBinding.msSampleMaxLocation >= 0) {
|
if (samplerBinding.msSampleMaxLocation >= 0) {
|
||||||
const Int sampleMax =
|
const Int sampleMax =
|
||||||
|
|||||||
@@ -107,12 +107,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
FramebufferImpl::InvalidateSyncedFramebufferSerial(target);
|
FramebufferImpl::InvalidateSyncedFramebufferSerial(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sized internal format of the currently bound READ framebuffer's read colour
|
// Sized internal format of the currently bound READ framebuffer's read color
|
||||||
// attachment, 0 when it cannot be determined.
|
// attachment, 0 when it cannot be determined.
|
||||||
static GLenum QueryReadColorAttachmentInternalFormat() {
|
static GLenum QueryReadColorAttachmentInternalFormat() {
|
||||||
GLint attachmentType = 0;
|
GLint attachmentType = 0;
|
||||||
GLint attachmentName = 0;
|
GLint attachmentName = 0;
|
||||||
// Ask the point the backend read buffer actually names, not COLOR_ATTACHMENT0. The colour map
|
// Ask the point the backend read buffer actually names, not COLOR_ATTACHMENT0. The color map
|
||||||
// in BackendFramebufferObject is a permutation, so the read attachment's image only sits at
|
// in BackendFramebufferObject is a permutation, so the read attachment's image only sits at
|
||||||
// CA0 when that map is identity; querying CA0 unconditionally would size the resolve
|
// CA0 when that map is identity; querying CA0 unconditionally would size the resolve
|
||||||
// renderbuffer from a different attachment's format and either convert wrongly or fail the
|
// renderbuffer from a different attachment's format and either convert wrongly or fail the
|
||||||
@@ -561,7 +561,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// The guard already left the pipeline neutral (nothing culled, tested, blended or
|
// The guard already left the pipeline neutral (nothing culled, tested, blended or
|
||||||
// coverage-masked) on the borrowed texture unit; what is left is this pass's own
|
// coverage-masked) on the borrowed texture unit; what is left is this pass's own
|
||||||
// choices - the destination rectangle, and colour writes off because it writes only
|
// choices - the destination rectangle, and color writes off because it writes only
|
||||||
// depth and stencil.
|
// depth and stencil.
|
||||||
VertexArrayImpl::BindBackendVAOId(s_vertexArray);
|
VertexArrayImpl::BindBackendVAOId(s_vertexArray);
|
||||||
g_GLESFuncs.glBindTexture(GL_TEXTURE_2D, s_texture);
|
g_GLESFuncs.glBindTexture(GL_TEXTURE_2D, s_texture);
|
||||||
@@ -626,7 +626,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// into a scratch framebuffer of the source's own native format, then run the caller's blit
|
// into a scratch framebuffer of the source's own native format, then run the caller's blit
|
||||||
// - same mask, same filter, same orientation - from the scratch into the real destination.
|
// - same mask, same filter, same orientation - from the scratch into the real destination.
|
||||||
// Overlapping rectangles stay undefined, as GL leaves them. A LINEAR blit that scales reads
|
// Overlapping rectangles stay undefined, as GL leaves them. A LINEAR blit that scales reads
|
||||||
// clamped texels at the rectangle's edge where GL would read the neighbouring ones.
|
// clamped texels at the rectangle's edge where GL would read the neighboring ones.
|
||||||
|
|
||||||
// What a framebuffer attachment point resolves to on the DRIVER side: the native object and,
|
// What a framebuffer attachment point resolves to on the DRIVER side: the native object and,
|
||||||
// for a texture, the level, layer and cube face. A null name means the point is empty.
|
// for a texture, the level, layer and cube face. A null name means the point is empty.
|
||||||
@@ -661,7 +661,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
a.Face == b.Face;
|
a.Face == b.Face;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The colour attachment point the bound READ framebuffer reads from, GL_NONE when it reads
|
// The color attachment point the bound READ framebuffer reads from, GL_NONE when it reads
|
||||||
// nothing.
|
// nothing.
|
||||||
static GLenum DriverReadColorAttachment() {
|
static GLenum DriverReadColorAttachment() {
|
||||||
GLint readBuffer = GL_NONE;
|
GLint readBuffer = GL_NONE;
|
||||||
@@ -878,7 +878,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousDraw);
|
g_GLESFuncs.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousDraw);
|
||||||
g_GLESFuncs.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previousRead);
|
g_GLESFuncs.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &previousRead);
|
||||||
|
|
||||||
// Every point is (re)attached on every call: the scratch is shared between colour and
|
// Every point is (re)attached on every call: the scratch is shared between color and
|
||||||
// depth/stencil shapes, and a stale attachment would make it incomplete or blit an
|
// depth/stencil shapes, and a stale attachment would make it incomplete or blit an
|
||||||
// aspect the source does not have.
|
// aspect the source does not have.
|
||||||
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_scratchFramebuffer);
|
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_scratchFramebuffer);
|
||||||
@@ -934,7 +934,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Two ES restrictions desktop GL does not have are worth a second attempt: a
|
// Two ES restrictions desktop GL does not have are worth a second attempt: a
|
||||||
// multisample resolve that also converts colour format, and any blit into a
|
// multisample resolve that also converts color format, and any blit into a
|
||||||
// multisample draw framebuffer. Both need to know how the two sides are sampled.
|
// multisample draw framebuffer. Both need to know how the two sides are sampled.
|
||||||
GLint readSamples = 0;
|
GLint readSamples = 0;
|
||||||
GLint drawSamples = 0;
|
GLint drawSamples = 0;
|
||||||
@@ -968,21 +968,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (ReplicateBlitIntoMultisampleDraw(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask)) {
|
if (ReplicateBlitIntoMultisampleDraw(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask)) {
|
||||||
if ((mask & GL_COLOR_BUFFER_BIT) != 0) {
|
if ((mask & GL_COLOR_BUFFER_BIT) != 0) {
|
||||||
MGLOG_E_ONCE(
|
MGLOG_E_ONCE(
|
||||||
"BlitFramebuffer: colour replicate into a multisample draw framebuffer is not emulated");
|
"BlitFramebuffer: color replicate into a multisample draw framebuffer is not emulated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The combined call raised an error, so by GL 4.6 2.3.1 it wrote nothing at all: BOTH
|
// The combined call raised an error, so by GL 4.6 2.3.1 it wrote nothing at all: BOTH
|
||||||
// aspect groups still owe their copy, and each has to be retried on its own. Re-issuing
|
// aspect groups still owe their copy, and each has to be retried on its own. Re-issuing
|
||||||
// the depth/stencil half only as a rider on a SUCCESSFUL colour resolve dropped it
|
// the depth/stencil half only as a rider on a SUCCESSFUL color resolve dropped it
|
||||||
// silently whenever the colour half could not be emulated - and on a framebuffer whose
|
// silently whenever the color half could not be emulated - and on a framebuffer whose
|
||||||
// only attachment is depth it never can, because the colour emulation has no attachment
|
// only attachment is depth it never can, because the color emulation has no attachment
|
||||||
// to take a format from (KHR-GL33.framebuffer_blit's depth config test blits
|
// to take a format from (KHR-GL33.framebuffer_blit's depth config test blits
|
||||||
// COLOR|DEPTH|STENCIL across depth-only framebuffers and kept reading the clear value).
|
// COLOR|DEPTH|STENCIL across depth-only framebuffers and kept reading the clear value).
|
||||||
const GLbitfield colourBit = mask & static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT);
|
const GLbitfield colourBit = mask & static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT);
|
||||||
const GLbitfield dsBits = mask & static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
const GLbitfield dsBits = mask & static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
// The colour group's one emulation is the multisample resolve that also converts format,
|
// The color group's one emulation is the multisample resolve that also converts format,
|
||||||
// which is the shape this names. It used to double as an early-out for the whole
|
// which is the shape this names. It used to double as an early-out for the whole
|
||||||
// function, which is what cost a depth-only mask its single-aspect retry.
|
// function, which is what cost a depth-only mask its single-aspect retry.
|
||||||
const Bool multisampleResolve = readSamples > 0 && drawSamples <= 0;
|
const Bool multisampleResolve = readSamples > 0 && drawSamples <= 0;
|
||||||
@@ -993,7 +993,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const Bool emulated = multisampleResolve &&
|
const Bool emulated = multisampleResolve &&
|
||||||
ResolveThenBlit(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, filter);
|
ResolveThenBlit(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, filter);
|
||||||
if (!emulated) {
|
if (!emulated) {
|
||||||
MGLOG_E_ONCE("BlitFramebuffer: the colour aspect was dropped - the driver rejected it on its "
|
MGLOG_E_ONCE("BlitFramebuffer: the color aspect was dropped - the driver rejected it on its "
|
||||||
"own and no emulation applies");
|
"own and no emulation applies");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1002,7 +1002,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
DrainBlitErrors();
|
DrainBlitErrors();
|
||||||
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, dsBits, filter);
|
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, dsBits, filter);
|
||||||
if (g_GLESFuncs.glGetError() != GL_NO_ERROR) {
|
if (g_GLESFuncs.glGetError() != GL_NO_ERROR) {
|
||||||
// Nothing to fall back on yet: ResolveThenBlit is colour-only and the replicate
|
// Nothing to fall back on yet: ResolveThenBlit is color-only and the replicate
|
||||||
// pass runs in the opposite direction, so a driver that declines a multisample
|
// pass runs in the opposite direction, so a driver that declines a multisample
|
||||||
// depth/stencil resolve leaves the destination holding its clear value. The log
|
// depth/stencil resolve leaves the destination holding its clear value. The log
|
||||||
// is the whole diagnostic - the frontend performs no validation of its own, so
|
// is the whole diagnostic - the frontend performs no validation of its own, so
|
||||||
@@ -1283,7 +1283,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
});
|
});
|
||||||
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
|
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0,
|
||||||
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
|
||||||
// A no-op on every driver that honours a non-zero destination array layer, which is all
|
// A no-op on every driver that honors a non-zero destination array layer, which is all
|
||||||
// of them but the probed one. Whatever it performs itself is taken out of the mask.
|
// of them but the probed one. Whatever it performs itself is taken out of the mask.
|
||||||
// P5e (fb, §5.4): the bound arm's two binding-slot reads were the last GetBoundObject
|
// P5e (fb, §5.4): the bound arm's two binding-slot reads were the last GetBoundObject
|
||||||
// pair on this path; under a transport the two bound RECORDS answer instead
|
// pair on this path; under a transport the two bound RECORDS answer instead
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// CountPrimitivesForDraw does not know and for the instanced/indirect entry
|
// CountPrimitivesForDraw does not know and for the instanced/indirect entry
|
||||||
// points that never call it.
|
// points that never call it.
|
||||||
MGLOG_E_ONCE("EndTransformFeedback: scattered capture discarded - packedStride=%zu, "
|
MGLOG_E_ONCE("EndTransformFeedback: scattered capture discarded - packedStride=%zu, "
|
||||||
"CPU-modelled captured vertices=%zu, scratch capacity=%zu. The capture buffers keep "
|
"CPU-modeled captured vertices=%zu, scratch capacity=%zu. The capture buffers keep "
|
||||||
"their pre-draw contents.",
|
"their pre-draw contents.",
|
||||||
packedStride, modelledVertices, xfb.scatterCapacityVertices);
|
packedStride, modelledVertices, xfb.scatterCapacityVertices);
|
||||||
return;
|
return;
|
||||||
@@ -431,7 +431,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// (glBufferData(size, NULL) with no resource_subdata since), which
|
// (glBufferData(size, NULL) with no resource_subdata since), which
|
||||||
// M-3 declares legal: every byte the application has not staged is
|
// M-3 declares legal: every byte the application has not staged is
|
||||||
// UNDEFINED by its own declaration, and `staged` is already
|
// UNDEFINED by its own declaration, and `staged` is already
|
||||||
// value-initialised to zero - which is byte for byte what the monolith
|
// value-initialized to zero - which is byte for byte what the monolith
|
||||||
// arm scatters over when it reads a fresh MappedData(). Skipping the
|
// arm scatters over when it reads a fresh MappedData(). Skipping the
|
||||||
// Memcpy is therefore the WHOLE of the difference; skipping the TARGET
|
// Memcpy is therefore the WHOLE of the difference; skipping the TARGET
|
||||||
// threw the varyings away and left the application's buffer holding its
|
// threw the varyings away and left the application's buffer holding its
|
||||||
@@ -669,7 +669,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The frontend VAO is taken ONLY when the applier's own vertex-buffer window says a
|
// The frontend VAO is taken ONLY when the applier's own vertex-buffer window says a
|
||||||
// client-sourced attribute exists, which is what retires the per-draw
|
// client-sourced attribute exists, which is what retires the per-draw
|
||||||
// GetBoundVertexArray row of the ordinary (VBO-backed) DrawArrays - the strict lane's
|
// GetBoundVertexArray row of the ordinary (VBO-backed) DrawArrays - the strict lane's
|
||||||
// `GetBoundVertexArray@DrawArrays` marker - without touching this path's behaviour.
|
// `GetBoundVertexArray@DrawArrays` marker - without touching this path's behavior.
|
||||||
// `static` on purpose (G1): the pull build must not gain an exported name for a
|
// `static` on purpose (G1): the pull build must not gain an exported name for a
|
||||||
// function that only re-homes two identical inline blocks the two DrawArrays entry
|
// function that only re-homes two identical inline blocks the two DrawArrays entry
|
||||||
// points used to carry. The same spelling governs the three below, and for a second
|
// points used to carry. The same spelling governs the three below, and for a second
|
||||||
|
|||||||
@@ -343,14 +343,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// default framebuffer is answered out of that guess, and being wrong is not cosmetic: GL
|
// default framebuffer is answered out of that guess, and being wrong is not cosmetic: GL
|
||||||
// blits depth/stencil only between IDENTICAL formats, so a caller that reads
|
// blits depth/stencil only between IDENTICAL formats, so a caller that reads
|
||||||
// GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, allocates the buffer it was told about and blits
|
// GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, allocates the buffer it was told about and blits
|
||||||
// gets GL_INVALID_OPERATION and a silently dropped blit - colour bits included, because a
|
// gets GL_INVALID_OPERATION and a silently dropped blit - color bits included, because a
|
||||||
// rejected glBlitFramebuffer transfers nothing at all. DirectVulkan already publishes its
|
// rejected glBlitFramebuffer transfers nothing at all. DirectVulkan already publishes its
|
||||||
// real format when it creates the swapchain (SwapchainObject::Create); this is the
|
// real format when it creates the swapchain (SwapchainObject::Create); this is the
|
||||||
// DirectGLES half, and here the answer can simply be asked of the ES default framebuffer.
|
// DirectGLES half, and here the answer can simply be asked of the ES default framebuffer.
|
||||||
//
|
//
|
||||||
// Only the format is published. The placeholder's 512x512 extent is left alone: all three
|
// Only the format is published. The placeholder's 512x512 extent is left alone: all three
|
||||||
// attachments share it, and FramebufferObject::CheckCompleteness requires them to agree, so
|
// attachments share it, and FramebufferObject::CheckCompleteness requires them to agree, so
|
||||||
// resizing depth/stencil without colour would report the default framebuffer incomplete.
|
// resizing depth/stencil without color would report the default framebuffer incomplete.
|
||||||
static void PublishDefaultFramebufferDepthStencilFormat() {
|
static void PublishDefaultFramebufferDepthStencilFormat() {
|
||||||
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
// P8-SE: THE PLACEHOLDER IS ONLY THE MONOLITH ARM'S TARGET. With a transport the answer is
|
// P8-SE: THE PLACEHOLDER IS ONLY THE MONOLITH ARM'S TARGET. With a transport the answer is
|
||||||
@@ -1550,7 +1550,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Clearing the global owner works from ANY thread (a release request can
|
// Clearing the global owner works from ANY thread (a release request can
|
||||||
// legally arrive on a thread other than the current owner); erring towards
|
// legally arrive on a thread other than the current owner); erring toward
|
||||||
// "not current" only defers buffer ops, which is always safe.
|
// "not current" only defers buffer ops, which is always safe.
|
||||||
InvalidateEglVerifiedStamp();
|
InvalidateEglVerifiedStamp();
|
||||||
t_native.boundContext = EGL_NO_CONTEXT;
|
t_native.boundContext = EGL_NO_CONTEXT;
|
||||||
|
|||||||
@@ -982,7 +982,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// P8-B2: RGB16F / RGB32F MIP GENERATION ON THE SERVER, FROM THE SERVER'S OWN LEVEL.
|
// P8-B2: RGB16F / RGB32F MIP GENERATION ON THE SERVER, FROM THE SERVER'S OWN LEVEL.
|
||||||
//
|
//
|
||||||
// ES generates a chain only for a colour-renderable, filterable format, and whether the
|
// ES generates a chain only for a color-renderable, filterable format, and whether the
|
||||||
// driver's storage for these two is one depends on the driver: Espryt stores them natively
|
// driver's storage for these two is one depends on the driver: Espryt stores them natively
|
||||||
// where the driver renders the three-channel form and widens them to RGBA16F / RGBA32F where
|
// where the driver renders the three-channel form and widens them to RGBA16F / RGBA32F where
|
||||||
// it does not (TextureImpl::BackendTextureFormatAddsAlpha), and a widened RGBA32F still needs
|
// it does not (TextureImpl::BackendTextureFormatAddsAlpha), and a widened RGBA32F still needs
|
||||||
@@ -1249,7 +1249,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
|
||||||
DebugImpl::OpenGLScopeMarker marker(__func__);
|
DebugImpl::OpenGLScopeMarker marker(__func__);
|
||||||
#endif
|
#endif
|
||||||
// P5e (tx2), CONTRACT-P5E §5.2 / ruling 14 (ID-92's neighbour): GENERATE_MIPMAP RESOLVES
|
// P5e (tx2), CONTRACT-P5E §5.2 / ruling 14 (ID-92's neighbor): GENERATE_MIPMAP RESOLVES
|
||||||
// ITS TEXTURE FROM VerbMipRes, NEVER FROM THE ACTIVE UNIT.
|
// ITS TEXTURE FROM VerbMipRes, NEVER FROM THE ACTIVE UNIT.
|
||||||
//
|
//
|
||||||
// The verb's own record names the texture (MGPMipPlan::Res, stashed as VerbMipRes) and
|
// The verb's own record names the texture (MGPMipPlan::Res, stashed as VerbMipRes) and
|
||||||
@@ -1634,7 +1634,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The frontend has already recorded the rebinding on the program object
|
// The frontend has already recorded the rebinding on the program object
|
||||||
// (SetShaderStorageBlockBinding) - that record is what GL_BUFFER_BINDING reports and what
|
// (SetShaderStorageBlockBinding) - that record is what GL_BUFFER_BINDING reports and what
|
||||||
// BackendProgramObjectImpl::SyncToBackend replays onto every driver program it builds. So
|
// BackendProgramObjectImpl::SyncToBackend replays onto every driver program it builds. So
|
||||||
// the only work left here is an optimisation: push the change straight onto a driver
|
// the only work left here is an optimization: push the change straight onto a driver
|
||||||
// program that is ALREADY built and already current with this link, so the next draw does
|
// program that is ALREADY built and already current with this link, so the next draw does
|
||||||
// not have to be preceded by a rebuild.
|
// not have to be preceded by a rebuild.
|
||||||
//
|
//
|
||||||
@@ -1667,7 +1667,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// A colour attachment the backend widened from three channels to four has to end up
|
// A color attachment the backend widened from three channels to four has to end up
|
||||||
// holding alpha 1.0 - the value GL reports for a channel the application's format does
|
// holding alpha 1.0 - the value GL reports for a channel the application's format does
|
||||||
// not have - so an explicit per-buffer clear of it writes 1.0 rather than whatever the
|
// not have - so an explicit per-buffer clear of it writes 1.0 rather than whatever the
|
||||||
// application passed (SubstituteWidenedClearAlpha, in Managers.h). Draws can never move
|
// application passed (SubstituteWidenedClearAlpha, in Managers.h). Draws can never move
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// P5e (mv): THE ARM SELECTOR of this family - VertexInputReadsRecords() - moved to
|
// P5e (mv): THE ARM SELECTOR of this family - VertexInputReadsRecords() - moved to
|
||||||
// Managers.h, unchanged. MultiDraw.cpp is a second translation unit on the same draw
|
// Managers.h, unchanged. MultiDraw.cpp is a second translation unit on the same draw
|
||||||
// path and has to select the same arm; a copy of the conjunction there would be two
|
// path and has to select the same arm; a copy of the conjunction there would be two
|
||||||
// selectors for one family. Its rationale travelled with it.
|
// selectors for one family. Its rationale traveled with it.
|
||||||
|
|
||||||
// P5e (vi): "does this draw fetch any attribute out of the application's own memory",
|
// P5e (vi): "does this draw fetch any attribute out of the application's own memory",
|
||||||
// answered FROM THE RECORD instead of from the frontend VAO. The emitter publishes
|
// answered FROM THE RECORD instead of from the frontend VAO. The emitter publishes
|
||||||
@@ -238,7 +238,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// feedback records per emitted primitive, so a replayed draw would write its vertices N
|
// feedback records per emitted primitive, so a replayed draw would write its vertices N
|
||||||
// times; rasterizer discard means there are no fragments to gate at all, so replaying
|
// times; rasterizer discard means there are no fragments to gate at all, so replaying
|
||||||
// would be pure cost with nothing to show for it. Both fall back to a single pass with an
|
// would be pure cost with nothing to show for it. Both fall back to a single pass with an
|
||||||
// open gate, i.e. to the pre-emulation behaviour, rather than to wrong data.
|
// open gate, i.e. to the pre-emulation behavior, rather than to wrong data.
|
||||||
if (MG_Pipe::gPipeInputs->IsTransformFeedbackActive() ||
|
if (MG_Pipe::gPipeInputs->IsTransformFeedbackActive() ||
|
||||||
MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) {
|
MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -521,7 +521,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#endif
|
#endif
|
||||||
TextureImpl::SyncNeccessaryTextures();
|
TextureImpl::SyncNeccessaryTextures();
|
||||||
FramebufferImpl::SyncCurrentFBO();
|
FramebufferImpl::SyncCurrentFBO();
|
||||||
// A colour clear is exactly the operation that is allowed to write a widened
|
// A color clear is exactly the operation that is allowed to write a widened
|
||||||
// attachment's alpha - it is what puts the 1.0 there that every later draw is masked
|
// attachment's alpha - it is what puts the 1.0 there that every later draw is masked
|
||||||
// away from. SyncCurrentFBO ran first, so g_alphaWidenedDrawBufferMask already describes
|
// away from. SyncCurrentFBO ran first, so g_alphaWidenedDrawBufferMask already describes
|
||||||
// the framebuffer this clear will land on.
|
// the framebuffer this clear will land on.
|
||||||
@@ -565,17 +565,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const Bool outOfRange = cc.x() < 0.f || cc.x() > 1.f || cc.y() < 0.f || cc.y() > 1.f || cc.z() < 0.f ||
|
const Bool outOfRange = cc.x() < 0.f || cc.x() > 1.f || cc.y() < 0.f || cc.y() > 1.f || cc.z() < 0.f ||
|
||||||
cc.z() > 1.f || cc.w() < 0.f || cc.w() > 1.f;
|
cc.z() > 1.f || cc.w() < 0.f || cc.w() > 1.f;
|
||||||
// A widened attachment's stored alpha has to end up 1.0, and glClear applies ONE
|
// A widened attachment's stored alpha has to end up 1.0, and glClear applies ONE
|
||||||
// clear colour to every draw buffer - so a framebuffer that mixes a widened
|
// clear color to every draw buffer - so a framebuffer that mixes a widened
|
||||||
// attachment with a native one cannot be served by doctoring glClearColor. Take the
|
// attachment with a native one cannot be served by doctoring glClearColor. Take the
|
||||||
// same per-draw-buffer glClearBufferfv route the out-of-range case already uses and
|
// same per-draw-buffer glClearBufferfv route the out-of-range case already uses and
|
||||||
// substitute the alpha only where it belongs. Scissor and the colour write mask apply
|
// substitute the alpha only where it belongs. Scissor and the color write mask apply
|
||||||
// to glClearBufferfv exactly as they do to glClear, so a scissored clear stays
|
// to glClearBufferfv exactly as they do to glClear, so a scissored clear stays
|
||||||
// scissored and an application that masked alpha off still gets its way (the storage
|
// scissored and an application that masked alpha off still gets its way (the storage
|
||||||
// then keeps the 1.0 an earlier clear left, which is the same answer).
|
// then keeps the 1.0 an earlier clear left, which is the same answer).
|
||||||
//
|
//
|
||||||
// glClearBufferfv on an INTEGER colour buffer is GL_INVALID_OPERATION, so a
|
// glClearBufferfv on an INTEGER color buffer is GL_INVALID_OPERATION, so a
|
||||||
// framebuffer with one of those as a draw buffer keeps plain glClear - which ES
|
// framebuffer with one of those as a draw buffer keeps plain glClear - which ES
|
||||||
// leaves undefined for integer colour buffers anyway, and which an application that
|
// leaves undefined for integer color buffers anyway, and which an application that
|
||||||
// wants a defined answer must replace with glClearBufferuiv/iv (those DO substitute
|
// wants a defined answer must replace with glClearBufferuiv/iv (those DO substitute
|
||||||
// the widened alpha). The out-of-range trigger is left exactly as it was.
|
// the widened alpha). The out-of-range trigger is left exactly as it was.
|
||||||
const Uint32 widenedDrawBuffers = FramebufferImpl::g_alphaWidenedDrawBufferMask;
|
const Uint32 widenedDrawBuffers = FramebufferImpl::g_alphaWidenedDrawBufferMask;
|
||||||
|
|||||||
@@ -611,9 +611,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
SamplerImpl::UnbindSampler(TextureImpl::TempTextureUnit);
|
SamplerImpl::UnbindSampler(TextureImpl::TempTextureUnit);
|
||||||
|
|
||||||
// The neutral baseline every emulation pass wants: nothing culled, nothing
|
// The neutral baseline every emulation pass wants: nothing culled, nothing
|
||||||
// clipped, nothing tested, no coverage games, and colour writes open. Callers
|
// clipped, nothing tested, no coverage games, and color writes open. Callers
|
||||||
// turn back on only what they need (the replicate pass wants the depth and
|
// turn back on only what they need (the replicate pass wants the depth and
|
||||||
// stencil tests, and masks colour off because it writes neither).
|
// stencil tests, and masks color off because it writes neither).
|
||||||
for (Uint i = 0; i < m_capabilityCount; ++i) {
|
for (Uint i = 0; i < m_capabilityCount; ++i) {
|
||||||
g_GLESFuncs.glDisable(m_capabilities[i].cap);
|
g_GLESFuncs.glDisable(m_capabilities[i].cap);
|
||||||
}
|
}
|
||||||
@@ -652,7 +652,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
g_GLESFuncs.glDisable(m_capabilities[i].cap);
|
g_GLESFuncs.glDisable(m_capabilities[i].cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The per-draw-buffer colour masks are not covered by the non-indexed
|
// The per-draw-buffer color masks are not covered by the non-indexed
|
||||||
// glColorMask above. Restore what the SYNC actually pushed, not the raw
|
// glColorMask above. Restore what the SYNC actually pushed, not the raw
|
||||||
// application masks: a widened attachment's alpha write is forced off by
|
// application masks: a widened attachment's alpha write is forced off by
|
||||||
// SyncRenderState and memoized in g_syncedColorMaskAlphaWidenMask, and the
|
// SyncRenderState and memoized in g_syncedColorMaskAlphaWidenMask, and the
|
||||||
@@ -886,7 +886,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DirectGLESReadback.cpp defines it: E's extent-scoped stand-in for a
|
// DirectGLESReadback.cpp defines it: E's extent-scoped stand-in for a
|
||||||
// driver that refuses to read a colour level back, asked here too so a host reaches the store
|
// driver that refuses to read a color level back, asked here too so a host reaches the store
|
||||||
// route below (P8-SE).
|
// route below (P8-SE).
|
||||||
Bool WireTextureReadbackRefusedForTesting(const IntVec3& extent);
|
Bool WireTextureReadbackRefusedForTesting(const IntVec3& extent);
|
||||||
using FramebufferImpl::SubstituteWidenedClearAlpha;
|
using FramebufferImpl::SubstituteWidenedClearAlpha;
|
||||||
|
|||||||
@@ -111,10 +111,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// it on the way). ES rejects a depth/stencil blit between differing formats, so
|
// it on the way). ES rejects a depth/stencil blit between differing formats, so
|
||||||
// the scratch has to match the source exactly; see DescribeReadDepthStencilSource.
|
// the scratch has to match the source exactly; see DescribeReadDepthStencilSource.
|
||||||
// 2. Convert. Draw a full-screen triangle that samples the staged texture into a
|
// 2. Convert. Draw a full-screen triangle that samples the staged texture into a
|
||||||
// scratch R32UI colour target: depth as floatBitsToUint (bit-exact for every depth
|
// scratch R32UI color target: depth as floatBitsToUint (bit-exact for every depth
|
||||||
// format, and an integer colour target needs no float-renderable extension),
|
// format, and an integer color target needs no float-renderable extension),
|
||||||
// stencil through GL_DEPTH_STENCIL_TEXTURE_MODE = GL_STENCIL_INDEX.
|
// stencil through GL_DEPTH_STENCIL_TEXTURE_MODE = GL_STENCIL_INDEX.
|
||||||
// 3. Read. glReadPixels the colour target with GL_RGBA_INTEGER / GL_UNSIGNED_INT -
|
// 3. Read. glReadPixels the color target with GL_RGBA_INTEGER / GL_UNSIGNED_INT -
|
||||||
// the pair ES guarantees for an unsigned-integer attachment - and hand the values
|
// the pair ES guarantees for an unsigned-integer attachment - and hand the values
|
||||||
// to the existing re-encoders, which already own the client-side (format, type)
|
// to the existing re-encoders, which already own the client-side (format, type)
|
||||||
// layout and the PACK pixel-store parameters.
|
// layout and the PACK pixel-store parameters.
|
||||||
@@ -407,7 +407,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (s_colorTexture == 0) return false;
|
if (s_colorTexture == 0) return false;
|
||||||
g_GLESFuncs.glBindTexture(GL_TEXTURE_2D, s_colorTexture);
|
g_GLESFuncs.glBindTexture(GL_TEXTURE_2D, s_colorTexture);
|
||||||
ClearGLErrors();
|
ClearGLErrors();
|
||||||
// R32UI is colour-renderable in ES 3.0 core - no float-renderability extension
|
// R32UI is color-renderable in ES 3.0 core - no float-renderability extension
|
||||||
// needed - and carries a depth bit pattern or a stencil index without loss.
|
// needed - and carries a depth bit pattern or a stencil index without loss.
|
||||||
g_GLESFuncs.glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, s_colorWidth, s_colorHeight);
|
g_GLESFuncs.glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, s_colorWidth, s_colorHeight);
|
||||||
const Bool ok = g_GLESFuncs.glGetError() == GL_NO_ERROR;
|
const Bool ok = g_GLESFuncs.glGetError() == GL_NO_ERROR;
|
||||||
@@ -458,7 +458,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs one conversion pass over a staged slot and reads its colour target back.
|
// Runs one conversion pass over a staged slot and reads its color target back.
|
||||||
// Requires the slot's texture bound on the borrowed unit and s_colorFramebuffer
|
// Requires the slot's texture bound on the borrowed unit and s_colorFramebuffer
|
||||||
// bound as DRAW.
|
// bound as DRAW.
|
||||||
static Bool ConvertAndRead(const StageSlot& slot, Bool stencilAspect, GLsizei width, GLsizei height,
|
static Bool ConvertAndRead(const StageSlot& slot, Bool stencilAspect, GLsizei width, GLsizei height,
|
||||||
@@ -625,7 +625,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Neither native spelling exists on this driver (which is the ordinary case: ES has
|
// Neither native spelling exists on this driver (which is the ordinary case: ES has
|
||||||
// no depth readback in core and GL_NV_read_depth is rare), so sample the attachment
|
// no depth readback in core and GL_NV_read_depth is rare), so sample the attachment
|
||||||
// instead. The scoped pack state above is irrelevant to that path - it reads its own
|
// instead. The scoped pack state above is irrelevant to that path - it reads its own
|
||||||
// scratch colour target - but harmless, and leaving it in place keeps the restore in
|
// scratch color target - but harmless, and leaving it in place keeps the restore in
|
||||||
// one place.
|
// one place.
|
||||||
if (DepthStencilSamplingReadImpl::Read(x, y, width, height, &outDepth, /*outStencil=*/nullptr)) {
|
if (DepthStencilSamplingReadImpl::Read(x, y, width, height, &outDepth, /*outStencil=*/nullptr)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -636,7 +636,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GL_DEPTH_COMPONENT readback into the client's layout, honouring the PACK pixel-store
|
// GL_DEPTH_COMPONENT readback into the client's layout, honoring the PACK pixel-store
|
||||||
// parameters. GL 4.6 core 18.2.8 table 8.6: the normalized depth is written as-is for the
|
// parameters. GL 4.6 core 18.2.8 table 8.6: the normalized depth is written as-is for the
|
||||||
// floating-point client types and scaled into the full range of whichever integer width the
|
// floating-point client types and scaled into the full range of whichever integer width the
|
||||||
// client asked for otherwise - 2^n - 1 for an unsigned width, 2^(n-1) - 1 for a signed one.
|
// client asked for otherwise - 2^n - 1 for an unsigned width, 2^(n-1) - 1 for a signed one.
|
||||||
@@ -764,7 +764,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GL_STENCIL_INDEX readback into the client's integer layout, honouring the PACK
|
// GL_STENCIL_INDEX readback into the client's integer layout, honoring the PACK
|
||||||
// pixel-store parameters. Handles the widths desktop clients ask for; the stencil
|
// pixel-store parameters. Handles the widths desktop clients ask for; the stencil
|
||||||
// values themselves are always 8 bits.
|
// values themselves are always 8 bits.
|
||||||
static Bool ReadPixelsStencilViaNative(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, void* pixels) {
|
static Bool ReadPixelsStencilViaNative(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, void* pixels) {
|
||||||
@@ -964,7 +964,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Overwrites the alpha of a 4-channel wide read with the format's implied 1.0. Used for an
|
// Overwrites the alpha of a 4-channel wide read with the format's implied 1.0. Used for an
|
||||||
// attachment the backend widened from three channels to keep it colour-renderable: the storage
|
// attachment the backend widened from three channels to keep it color-renderable: the storage
|
||||||
// has a real alpha channel holding whatever the draw wrote, but the format the application
|
// has a real alpha channel holding whatever the draw wrote, but the format the application
|
||||||
// asked for has none, and GL reads a missing channel back as one.
|
// asked for has none, and GL reads a missing channel back as one.
|
||||||
static void ForceWideReadAlphaToOne(Vector<Uint8>& data, SizeT pixelCount, GLenum componentType) {
|
static void ForceWideReadAlphaToOne(Vector<Uint8>& data, SizeT pixelCount, GLenum componentType) {
|
||||||
@@ -1033,7 +1033,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// (format, type) layout. Returns false when the combination is not convertible (the caller keeps its
|
// (format, type) layout. Returns false when the combination is not convertible (the caller keeps its
|
||||||
// "not implemented" skip); returns true when the request was handled, even if it degraded to a logged no-op.
|
// "not implemented" skip); returns true when the request was handled, even if it degraded to a logged no-op.
|
||||||
// `forceOpaqueAlpha`: the source image is a three-channel format the backend widened to four to
|
// `forceOpaqueAlpha`: the source image is a three-channel format the backend widened to four to
|
||||||
// keep it colour-renderable, so its alpha channel holds whatever the draw wrote and has to be
|
// keep it color-renderable, so its alpha channel holds whatever the draw wrote and has to be
|
||||||
// answered with the 1.0 the application's format implies. Passed in rather than derived here:
|
// answered with the 1.0 the application's format implies. Passed in rather than derived here:
|
||||||
// glReadPixels reads the bound READ framebuffer, but glGetTexImage reads a texture through a
|
// glReadPixels reads the bound READ framebuffer, but glGetTexImage reads a texture through a
|
||||||
// scratch framebuffer, so the frontend's READ binding describes a different image entirely -
|
// scratch framebuffer, so the frontend's READ binding describes a different image entirely -
|
||||||
@@ -1230,7 +1230,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
ForceWideReadAlphaToOne(wide, static_cast<SizeT>(width) * static_cast<SizeT>(height), wideType);
|
ForceWideReadAlphaToOne(wide, static_cast<SizeT>(width) * static_cast<SizeT>(height), wideType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GL clamps a read from a fixed-point colour buffer to [0,1] (GL_CLAMP_READ_COLOR
|
// GL clamps a read from a fixed-point color buffer to [0,1] (GL_CLAMP_READ_COLOR
|
||||||
// defaults to GL_FIXED_ONLY). Formats the backend substitutes with a floating-point
|
// defaults to GL_FIXED_ONLY). Formats the backend substitutes with a floating-point
|
||||||
// one keep the out-of-range value the app stored, so apply the clamp here - a
|
// one keep the out-of-range value the app stored, so apply the clamp here - a
|
||||||
// GL_R16_SNORM target holding -0.125 must still read back as 0.
|
// GL_R16_SNORM target holding -0.125 must still read back as 0.
|
||||||
@@ -1283,13 +1283,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Bit-exact readback of a 32-bit packed colour level ---------------------------------------
|
// ---- Bit-exact readback of a 32-bit packed color level ---------------------------------------
|
||||||
//
|
//
|
||||||
// glGetTexImage of a packed format read with its OWN client type owes the application the words
|
// glGetTexImage of a packed format read with its OWN client type owes the application the words
|
||||||
// the image HOLDS, and neither of the two routes above can promise that once anything other than
|
// the image HOLDS, and neither of the two routes above can promise that once anything other than
|
||||||
// a glTexImage has written the level:
|
// a glTexImage has written the level:
|
||||||
//
|
//
|
||||||
// * the colour-attachment route reads GL_RGBA/GL_FLOAT and re-encodes, which canonicalizes an
|
// * the color-attachment route reads GL_RGBA/GL_FLOAT and re-encodes, which canonicalizes an
|
||||||
// RGB9_E5 shared exponent (0xf8fc0000 -> 0xe7e00000, same value, different bits) and
|
// RGB9_E5 shared exponent (0xf8fc0000 -> 0xe7e00000, same value, different bits) and
|
||||||
// collapses an R11F_G11F_B10F NaN to the canonical payload 1
|
// collapses an R11F_G11F_B10F NaN to the canonical payload 1
|
||||||
// (MG_Util::EncodeFloatToUnsignedSmallFloat) - and a copy-image from RGB9_E5 lands exactly
|
// (MG_Util::EncodeFloatToUnsignedSmallFloat) - and a copy-image from RGB9_E5 lands exactly
|
||||||
@@ -1301,7 +1301,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// source (which has no shadow to mirror from at all), a cube or 1D-array endpoint, a
|
// source (which has no shadow to mirror from at all), a cube or 1D-array endpoint, a
|
||||||
// self-copy - and the decline is silent, so the stale words are served as truth.
|
// self-copy - and the decline is silent, so the stale words are served as truth.
|
||||||
//
|
//
|
||||||
// glCopyImageSubData is a raw texel-block move and EXT_copy_image puts every 32-bit colour
|
// glCopyImageSubData is a raw texel-block move and EXT_copy_image puts every 32-bit color
|
||||||
// format in one compatibility class, so copying the level into a scratch GL_R32UI image and
|
// format in one compatibility class, so copying the level into a scratch GL_R32UI image and
|
||||||
// reading THAT back as unsigned integers hands over the stored words themselves, whoever wrote
|
// reading THAT back as unsigned integers hands over the stored words themselves, whoever wrote
|
||||||
// them. This is what lets the shadow stop being the authority for these formats: it is tried
|
// them. This is what lets the shadow stop being the authority for these formats: it is tried
|
||||||
@@ -1387,7 +1387,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GL_RGBA_INTEGER/GL_UNSIGNED_INT is the one combination ES guarantees for an integer
|
// GL_RGBA_INTEGER/GL_UNSIGNED_INT is the one combination ES guarantees for an integer
|
||||||
// colour buffer, so the read lands four words per texel and the red one is compacted out
|
// color buffer, so the read lands four words per texel and the red one is compacted out
|
||||||
// here. The PACK scope is the tight default rather than the application's, so a row comes
|
// here. The PACK scope is the tight default rather than the application's, so a row comes
|
||||||
// back packed at exactly `width * 4` words. One glGetError covers the whole loop: it
|
// back packed at exactly `width * 4` words. One glGetError covers the whole loop: it
|
||||||
// accumulates, and a failure anywhere means the caller falls back rather than trusting a
|
// accumulates, and a failure anywhere means the caller falls back rather than trusting a
|
||||||
@@ -1796,7 +1796,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// P8-E. MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT=<w>x<h>, READ BY THE SERVER:
|
// P8-E. MGITEST_ESPRYT_REFUSE_TEXTURE_READBACK_EXTENT=<w>x<h>, READ BY THE SERVER:
|
||||||
// a colour level of exactly that extent is treated as one the driver refused to attach - what an
|
// a color level of exactly that extent is treated as one the driver refused to attach - what an
|
||||||
// Adreno does for RGB16 and the 16-bit SNORM formats, and what no host driver can be made to do.
|
// Adreno does for RGB16 and the 16-bit SNORM formats, and what no host driver can be made to do.
|
||||||
// Scoped by the extent so the tcp lane's shared supervisor can carry it for the whole lane: only
|
// Scoped by the extent so the tcp lane's shared supervisor can carry it for the whole lane: only
|
||||||
// the scenario that builds that extent (CopyImageStoreReadbackScenario) ever meets it.
|
// the scenario that builds that extent (CopyImageStoreReadbackScenario) ever meets it.
|
||||||
@@ -1954,7 +1954,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The (format, type) pairs the depth/stencil helpers below can service. They are not
|
// The (format, type) pairs the depth/stencil helpers below can service. They are not
|
||||||
// covered by the colour tables above - GetReadbackChannelMapping has no entry for any
|
// covered by the color tables above - GetReadbackChannelMapping has no entry for any
|
||||||
// depth or stencil format, so without this gate a read the helpers CAN serve (a
|
// depth or stencil format, so without this gate a read the helpers CAN serve (a
|
||||||
// GL_UNSIGNED_SHORT depth, a GL_SHORT stencil) is turned away before it reaches them.
|
// GL_UNSIGNED_SHORT depth, a GL_SHORT stencil) is turned away before it reaches them.
|
||||||
// The signed widths and GL_HALF_FLOAT belong in it for the same reason: the helpers scale a
|
// The signed widths and GL_HALF_FLOAT belong in it for the same reason: the helpers scale a
|
||||||
@@ -2025,7 +2025,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The read buffer is what glReadPixels reads, so the frontend's READ binding is exactly
|
// The read buffer is what glReadPixels reads, so the frontend's READ binding is exactly
|
||||||
// the right thing to ask here.
|
// the right thing to ask here.
|
||||||
const Bool forceOpaqueAlpha = FramebufferImpl::IsAlphaWidenedFallbackReadAttachment();
|
const Bool forceOpaqueAlpha = FramebufferImpl::IsAlphaWidenedFallbackReadAttachment();
|
||||||
// An attachment widened from three channels to stay colour-renderable also has to leave
|
// An attachment widened from three channels to stay color-renderable also has to leave
|
||||||
// the fast pair: only the conversion path knows to answer its alpha with the 1.0 the
|
// the fast pair: only the conversion path knows to answer its alpha with the 1.0 the
|
||||||
// application's format implies instead of whatever the draw wrote into the added channel.
|
// application's format implies instead of whatever the draw wrote into the added channel.
|
||||||
const Bool nativeFastPair = !packSwapBytes && !forceOpaqueAlpha &&
|
const Bool nativeFastPair = !packSwapBytes && !forceOpaqueAlpha &&
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
DupNativeFenceFdFn DupNativeFenceFd = nullptr;
|
DupNativeFenceFdFn DupNativeFenceFd = nullptr;
|
||||||
// YUV images: sampled as external textures (GL_OES_EGL_image_external_essl3), and
|
// YUV images: sampled as external textures (GL_OES_EGL_image_external_essl3), and
|
||||||
// through GL_EXT_YUV_target's raw Y'CbCr sampler where the driver has it, so the
|
// through GL_EXT_YUV_target's raw Y'CbCr sampler where the driver has it, so the
|
||||||
// conversion is the import's own (its colour hints) rather than the driver's guess.
|
// conversion is the import's own (its color hints) rather than the driver's guess.
|
||||||
Bool ExternalEssl3 = false;
|
Bool ExternalEssl3 = false;
|
||||||
Bool YuvTarget = false;
|
Bool YuvTarget = false;
|
||||||
};
|
};
|
||||||
@@ -573,7 +573,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
conversion.TargetOffset = g_GLESFuncs.glGetUniformLocation(program, "uOffset");
|
conversion.TargetOffset = g_GLESFuncs.glGetUniformLocation(program, "uOffset");
|
||||||
}
|
}
|
||||||
MGLOG_I("Shared images: YUV images convert through %s",
|
MGLOG_I("Shared images: YUV images convert through %s",
|
||||||
ownConversion ? "GL_EXT_YUV_target with the import's colour hints"
|
ownConversion ? "GL_EXT_YUV_target with the import's color hints"
|
||||||
: "the driver's external-sampler conversion");
|
: "the driver's external-sampler conversion");
|
||||||
}
|
}
|
||||||
if (conversion.Framebuffer == 0) g_GLESFuncs.glGenFramebuffers(1, &conversion.Framebuffer);
|
if (conversion.Framebuffer == 0) g_GLESFuncs.glGenFramebuffers(1, &conversion.Framebuffer);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// The cache stays on the LEGACY arm, gated on the same subsystem bit as the rest of this
|
// The cache stays on the LEGACY arm, gated on the same subsystem bit as the rest of this
|
||||||
// slice, so that MOBILEGL_PIPE_PUSH=0 keeps being the faithful all-subsystems-pull control
|
// slice, so that MOBILEGL_PIPE_PUSH=0 keeps being the faithful all-subsystems-pull control
|
||||||
// ConfigLoader.cpp documents - "reproduces P1's behaviour exactly" has to include this
|
// ConfigLoader.cpp documents - "reproduces P1's behavior exactly" has to include this
|
||||||
// path, or the integrator's A/B measures e4 on both arms and attributes it to neither. In
|
// path, or the integrator's A/B measures e4 on both arms and attributes it to neither. In
|
||||||
// the pull build gPipeInputs is the live GLContext, there is no poison to bypass and the
|
// the pull build gPipeInputs is the live GLContext, there is no poison to bypass and the
|
||||||
// frontend getter still linear-scans, so the cache is exactly the code it was.
|
// frontend getter still linear-scans, so the cache is exactly the code it was.
|
||||||
@@ -339,9 +339,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// direct_state_access.renderbuffers_storage. One unconditional push settles the whole
|
// direct_state_access.renderbuffers_storage. One unconditional push settles the whole
|
||||||
// block rather than the one cap that happened to be noticed.
|
// block rather than the one cap that happened to be noticed.
|
||||||
static Bool g_forceFullRenderStateResync = true;
|
static Bool g_forceFullRenderStateResync = true;
|
||||||
// Which draw buffers' alpha channel the colour mask last pushed to the driver had forced
|
// Which draw buffers' alpha channel the color mask last pushed to the driver had forced
|
||||||
// OFF - i.e. the value of `appliedWidenMask` in the last SyncRenderState that reached the
|
// OFF - i.e. the value of `appliedWidenMask` in the last SyncRenderState that reached the
|
||||||
// colour-mask block. NOT derivable from the frontend parameter block: it depends on the
|
// color-mask block. NOT derivable from the frontend parameter block: it depends on the
|
||||||
// bound DRAW framebuffer's attachment formats and on whether the caller is a draw or a
|
// bound DRAW framebuffer's attachment formats and on whether the caller is a draw or a
|
||||||
// clear, neither of which bumps the frontend render-state version. Without it a
|
// clear, neither of which bumps the frontend render-state version. Without it a
|
||||||
// clear-then-draw pair on an unchanged parameter block early-outs and the draw inherits
|
// clear-then-draw pair on an unchanged parameter block early-outs and the draw inherits
|
||||||
@@ -405,7 +405,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Uint16 currentRenderStateVersion = MG_Pipe::gPipeInputs->GetRenderStateParametersVersion();
|
Uint16 currentRenderStateVersion = MG_Pipe::gPipeInputs->GetRenderStateParametersVersion();
|
||||||
const Bool forceFullPush = g_forceFullRenderStateResync;
|
const Bool forceFullPush = g_forceFullRenderStateResync;
|
||||||
g_forceFullRenderStateResync = false;
|
g_forceFullRenderStateResync = false;
|
||||||
// The alpha discipline for widened colour attachments (see the header comment on
|
// The alpha discipline for widened color attachments (see the header comment on
|
||||||
// SyncRenderState): a DRAW must not be able to move the stored alpha off 1.0, a CLEAR
|
// SyncRenderState): a DRAW must not be able to move the stored alpha off 1.0, a CLEAR
|
||||||
// is what puts it there. So the draw path masks alpha off on every widened draw
|
// is what puts it there. So the draw path masks alpha off on every widened draw
|
||||||
// buffer and the clear path masks nothing.
|
// buffer and the clear path masks nothing.
|
||||||
@@ -539,7 +539,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
{ // sRGB framebuffer writes. GLES core always encodes a write into an sRGB attachment,
|
{ // sRGB framebuffer writes. GLES core always encodes a write into an sRGB attachment,
|
||||||
// while GL_FRAMEBUFFER_SRGB is disabled by default in desktop GL and the frontend
|
// while GL_FRAMEBUFFER_SRGB is disabled by default in desktop GL and the frontend
|
||||||
// never turns it on, so the driver has to be told to write raw. Without this a render
|
// never turns it on, so the driver has to be told to write raw. Without this a render
|
||||||
// into an sRGB colour buffer comes back encoded once too often (the shader's own
|
// into an sRGB color buffer comes back encoded once too often (the shader's own
|
||||||
// decode on the next fetch then leaves the value one conversion short).
|
// decode on the next fetch then leaves the value one conversion short).
|
||||||
const Bool srgbWrites = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb);
|
const Bool srgbWrites = MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::FramebufferSrgb);
|
||||||
if (g_GLESCapabilities.SupportsSrgbWriteControl &&
|
if (g_GLESCapabilities.SupportsSrgbWriteControl &&
|
||||||
@@ -853,7 +853,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// framebuffer, so a widened draw buffer 0 costs every other buffer its
|
// framebuffer, so a widened draw buffer 0 costs every other buffer its
|
||||||
// alpha writes. ES 3.2 makes glColorMaski core and ES 3.1 has it as
|
// alpha writes. ES 3.2 makes glColorMaski core and ES 3.1 has it as
|
||||||
// EXT/OES; the only devices that reach this line are ES 3.0-class, where
|
// EXT/OES; the only devices that reach this line are ES 3.0-class, where
|
||||||
// MRT with a mixed widened/native colour attachment set is already rare.
|
// MRT with a mixed widened/native color attachment set is already rare.
|
||||||
const BoolVec4& m = driverMask0;
|
const BoolVec4& m = driverMask0;
|
||||||
g_GLESFuncs.glColorMask(ToGLBoolean(m.x()), ToGLBoolean(m.y()), ToGLBoolean(m.z()),
|
g_GLESFuncs.glColorMask(ToGLBoolean(m.x()), ToGLBoolean(m.y()), ToGLBoolean(m.z()),
|
||||||
ToGLBoolean(m.w()));
|
ToGLBoolean(m.w()));
|
||||||
|
|||||||
@@ -601,7 +601,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// spelling the driver provides (Adreno exposes only eglSwapBuffersWithDamageKHR), so
|
// spelling the driver provides (Adreno exposes only eglSwapBuffersWithDamageKHR), so
|
||||||
// the null check below is the whole chain: a driver with neither presents with plain
|
// the null check below is the whole chain: a driver with neither presents with plain
|
||||||
// eglSwapBuffers. Passing n_rects == 0 is not a partial present - the extension
|
// eglSwapBuffers. Passing n_rects == 0 is not a partial present - the extension
|
||||||
// defines it as "the entire surface is implicitly damaged and the behaviour is
|
// defines it as "the entire surface is implicitly damaged and the behavior is
|
||||||
// equivalent to calling eglSwapBuffers" - and the wire protocol carries no damage
|
// equivalent to calling eglSwapBuffers" - and the wire protocol carries no damage
|
||||||
// rectangles for the server to forward, so the full surface is what is meant anyway.
|
// rectangles for the server to forward, so the full surface is what is meant anyway.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// two never-synced textures as equal. The identity has to exist before the twin does.
|
// two never-synced textures as equal. The identity has to exist before the twin does.
|
||||||
//
|
//
|
||||||
// Split by the RUNTIME arm, not by the build, for exactly the reason g_fbSlotCache is:
|
// Split by the RUNTIME arm, not by the build, for exactly the reason g_fbSlotCache is:
|
||||||
// MOBILEGL_PIPE_PUSH=0 has to reproduce P1's behaviour (ConfigLoader.cpp), and a
|
// MOBILEGL_PIPE_PUSH=0 has to reproduce P1's behavior (ConfigLoader.cpp), and a
|
||||||
// legacy-arm run that debounced on lifetime ids would be running P2's mechanism while
|
// legacy-arm run that debounced on lifetime ids would be running P2's mechanism while
|
||||||
// the A/B attributed the result to P1. The two answers are equivalent - OwnerEquals on
|
// the A/B attributed the result to P1. The two answers are equivalent - OwnerEquals on
|
||||||
// two empty pointers is true and LifetimeIdOf(nullptr) == 0 == 0; a live-versus-expired
|
// two empty pointers is true and LifetimeIdOf(nullptr) == 0 == 0; a live-versus-expired
|
||||||
@@ -454,7 +454,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// A texture that is an attachment of the READ framebuffer ONLY reaches
|
// A texture that is an attachment of the READ framebuffer ONLY reaches
|
||||||
// SyncAttachmentObject, which calls SyncMipmapsToBackend AND NOTHING ELSE - so its
|
// SyncAttachmentObject, which calls SyncMipmapsToBackend AND NOTHING ELSE - so its
|
||||||
// swizzle, its GL_DEPTH_STENCIL_TEXTURE_MODE, its LOD clamp and its border colour
|
// swizzle, its GL_DEPTH_STENCIL_TEXTURE_MODE, its LOD clamp and its border color
|
||||||
// never reach the driver. The list that pushes texture PARAMETERS for an attachment is
|
// never reach the driver. The list that pushes texture PARAMETERS for an attachment is
|
||||||
// the one below, and it reads the DRAW binding slot alone. That is the gap
|
// the one below, and it reads the DRAW binding slot alone. That is the gap
|
||||||
// ARCHITECTURE.md's D10 names, and the roadmap makes closing it a mandatory,
|
// ARCHITECTURE.md's D10 names, and the roadmap makes closing it a mandatory,
|
||||||
@@ -464,7 +464,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// DELIBERATELY NOT GATED ON THE FRAMEBUFFER SUBSYSTEM BIT. It is a deliverable of the
|
// DELIBERATELY NOT GATED ON THE FRAMEBUFFER SUBSYSTEM BIT. It is a deliverable of the
|
||||||
// phase rather than an arm of it, so both arms of the object A/B carry it and the A/B
|
// phase rather than an arm of it, so both arms of the object A/B carry it and the A/B
|
||||||
// keeps measuring the arm rather than the arm plus a behaviour change. It is inside
|
// keeps measuring the arm rather than the arm plus a behavior change. It is inside
|
||||||
// MOBILEGL_PIPE_PUSH, so the pull build is untouched.
|
// MOBILEGL_PIPE_PUSH, so the pull build is untouched.
|
||||||
//
|
//
|
||||||
// Its own list and its own key rather than an extension of the draw list's, because
|
// Its own list and its own key rather than an extension of the draw list's, because
|
||||||
@@ -562,7 +562,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// and the alias contest between two real textures on one native target was arbitrated
|
// and the alias contest between two real textures on one native target was arbitrated
|
||||||
// by the program's own sampler types. So the window IS the work list.
|
// by the program's own sampler types. So the window IS the work list.
|
||||||
//
|
//
|
||||||
// NAMED BEHAVIOUR DELTA (P5e-5, contract §5.2): this syncs the PROGRAM-RESOLVED
|
// NAMED BEHAVIOR DELTA (P5e-5, contract §5.2): this syncs the PROGRAM-RESOLVED
|
||||||
// texture per unit, where the frontend walk syncs every slot of every touched unit.
|
// texture per unit, where the frontend walk syncs every slot of every touched unit.
|
||||||
// Coverage is unchanged - views UNION image units UNION the FBO attachment lists
|
// Coverage is unchanged - views UNION image units UNION the FBO attachment lists
|
||||||
// UNION the waited texture ops still cover every texture anything reads - so it
|
// UNION the waited texture ops still cover every texture anything reads - so it
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// InProcessTeardown() - touches neither the driver nor another TU's statics.
|
// InProcessTeardown() - touches neither the driver nor another TU's statics.
|
||||||
//
|
//
|
||||||
// P14 S6: "EVERY TABLE" IS NOW "EVERY BUCKET OF THIS SESSION". The tables are keyed by
|
// P14 S6: "EVERY TABLE" IS NOW "EVERY BUCKET OF THIS SESSION". The tables are keyed by
|
||||||
// {session, share group}, so the same rebuild of the eight registries would take a NEIGHBOUR
|
// {session, share group}, so the same rebuild of the eight registries would take a NEIGHBOR
|
||||||
// session's twins with it - and with S2's in-process supervisor serving several sessions at
|
// session's twins with it - and with S2's in-process supervisor serving several sessions at
|
||||||
// once that is not a hypothetical: this runs from ~BackendObject_DirectGLES, on the apply
|
// once that is not a hypothetical: this runs from ~BackendObject_DirectGLES, on the apply
|
||||||
// thread of the session that is ending. So the drop is scoped to the calling thread's
|
// thread of the session that is ending. So the drop is scoped to the calling thread's
|
||||||
@@ -533,7 +533,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// Fragment stage. Returns false when the stage has no entry point to gate onto, which the
|
// Fragment stage. Returns false when the stage has no entry point to gate onto, which the
|
||||||
// caller reports: the program still links and still renders, it just renders every index
|
// caller reports: the program still links and still renders, it just renders every index
|
||||||
// with the first replay pass's state - i.e. it degrades to the pre-emulation behaviour
|
// with the first replay pass's state - i.e. it degrades to the pre-emulation behavior
|
||||||
// rather than to a black screen.
|
// rather than to a black screen.
|
||||||
Bool InjectViewportIndexPassGate(String& source) {
|
Bool InjectViewportIndexPassGate(String& source) {
|
||||||
// Built beside the input and swapped in only on success, so a stage this pass declines
|
// Built beside the input and swapped in only on success, so a stage this pass declines
|
||||||
@@ -879,7 +879,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
"MGPFramebufferState::Color[%u]'s wire width",
|
"MGPFramebufferState::Color[%u]'s wire width",
|
||||||
cap, MG_Pipe::kMGPipeMaxColorAttachments);
|
cap, MG_Pipe::kMGPipeMaxColorAttachments);
|
||||||
BufferImpl::StopOnArmlessPipeSubsystem(
|
BufferImpl::StopOnArmlessPipeSubsystem(
|
||||||
"kMGPipeSubsystemFramebuffer (bit 9) cannot carry this driver's colour attachments, and "
|
"kMGPipeSubsystemFramebuffer (bit 9) cannot carry this driver's color attachments, and "
|
||||||
"the record arm is the only arm since P13 W6");
|
"the record arm is the only arm since P13 W6");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -914,7 +914,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (!TextureImpl::IsMultisampleTextureTarget(target)) return 0;
|
if (!TextureImpl::IsMultisampleTextureTarget(target)) return 0;
|
||||||
// The same three inputs the storage allocation clamps with (SyncToBackend's multisample
|
// The same three inputs the storage allocation clamps with (SyncToBackend's multisample
|
||||||
// arm): the record's format and requested count, and the format's ES transfer format,
|
// arm): the record's format and requested count, and the format's ES transfer format,
|
||||||
// which only decides the integer-vs-colour fallback when the probe has no answer.
|
// which only decides the integer-vs-color fallback when the probe has no answer.
|
||||||
const auto internalFormat = static_cast<TextureInternalFormat>(record->Desc.InternalFormat);
|
const auto internalFormat = static_cast<TextureInternalFormat>(record->Desc.InternalFormat);
|
||||||
GLenum glInternalFormat = 0, glFormat = 0, glType = 0;
|
GLenum glInternalFormat = 0, glFormat = 0, glType = 0;
|
||||||
TextureImpl::GenerateTextureFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType, target);
|
TextureImpl::GenerateTextureFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType, target);
|
||||||
@@ -931,7 +931,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// N-7: D KEYS ON THE UPLOAD HALF; WIRE (AccumulatePendingUpload, PipeApply.cpp) KEYS ON
|
// N-7: D KEYS ON THE UPLOAD HALF; WIRE (AccumulatePendingUpload, PipeApply.cpp) KEYS ON
|
||||||
// THE WHOLE PACKED FIELD. That asymmetry is resolved HERE, in D's favour and with the
|
// THE WHOLE PACKED FIELD. That asymmetry is resolved HERE, in D's favor and with the
|
||||||
// reason, rather than by widening the two comparisons: D's question is per (uploadTarget,
|
// reason, rather than by widening the two comparisons: D's question is per (uploadTarget,
|
||||||
// level) because that is the granularity its upload loop iterates - it is handed a
|
// level) because that is the granularity its upload loop iterates - it is handed a
|
||||||
// TextureUploadTarget and a level and has no second key to offer - while wire's is per
|
// TextureUploadTarget and a level and has no second key to offer - while wire's is per
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
GLenum IndexType() const { return m_indexType; }
|
GLenum IndexType() const { return m_indexType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Declared before m_capOverride so it is initialised first (members initialise in
|
// Declared before m_capOverride so it is initialized first (members initialize in
|
||||||
// declaration order): the whole decision is made once, and both the cap override and the
|
// declaration order): the whole decision is made once, and both the cap override and the
|
||||||
// constructor body read the same answer.
|
// constructor body read the same answer.
|
||||||
RestartSubstitutionKind m_kind = RestartSubstitutionKind::None;
|
RestartSubstitutionKind m_kind = RestartSubstitutionKind::None;
|
||||||
@@ -248,7 +248,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Indices whose whole state tuple (viewport rectangle, scissor rectangle, scissor-test enable,
|
// Indices whose whole state tuple (viewport rectangle, scissor rectangle, scissor-test enable,
|
||||||
// depth range) is identical share ONE pass, so the overwhelmingly common case - every index
|
// depth range) is identical share ONE pass, so the overwhelmingly common case - every index
|
||||||
// still holding what glViewport/glScissor/glDepthRange broadcast to all sixteen - collapses
|
// still holding what glViewport/glScissor/glDepthRange broadcast to all sixteen - collapses
|
||||||
// to a single pass with an all-ones gate mask, i.e. one draw and no behaviour change at all.
|
// to a single pass with an all-ones gate mask, i.e. one draw and no behavior change at all.
|
||||||
//
|
//
|
||||||
// Whether emulation runs. Off only under MOBILEGL_ESPRYT_FORCE_VIEWPORT_ARRAY_EMULATION falsy, which
|
// Whether emulation runs. Off only under MOBILEGL_ESPRYT_FORCE_VIEWPORT_ARRAY_EMULATION falsy, which
|
||||||
// restores the pre-emulation path as a negative control.
|
// restores the pre-emulation path as a negative control.
|
||||||
@@ -527,7 +527,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Bool ResolveProgramSubsystemArm();
|
Bool ResolveProgramSubsystemArm();
|
||||||
// P13 W6: every family runs the record arm - the frontend arms these resolvers used to choose
|
// P13 W6: every family runs the record arm - the frontend arms these resolvers used to choose
|
||||||
// between are gone, so no draw-path site asks them any more (the integration peeks still read
|
// between are gone, so no draw-path site asks them any more (the integration peeks still read
|
||||||
// the latches). The one refusal a running process can still meet - a driver whose colour-
|
// the latches). The one refusal a running process can still meet - a driver whose color-
|
||||||
// attachment cap exceeds the wire's width - is checked once, at capability bring-up.
|
// attachment cap exceeds the wire's width - is checked once, at capability bring-up.
|
||||||
void ResolveRecordArmFamilies();
|
void ResolveRecordArmFamilies();
|
||||||
|
|
||||||
@@ -843,7 +843,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// glBufferStorageExternalEXT, so `id` is immutable, persistentMapped and
|
// glBufferStorageExternalEXT, so `id` is immutable, persistentMapped and
|
||||||
// persistentPtr is this server's own coherent map of the client's pages. The
|
// persistentPtr is this server's own coherent map of the client's pages. The
|
||||||
// reference is this twin's own, released only after a fence that follows the
|
// reference is this twin's own, released only after a fence that follows the
|
||||||
// store's last use has signalled (RetireT0Import). Survives an ES context loss:
|
// store's last use has signaled (RetireT0Import). Survives an ES context loss:
|
||||||
// the next ensure re-imports it. Null for every store T0 did not adopt.
|
// the next ensure re-imports it. Null for every store T0 did not adopt.
|
||||||
void* externalAhb = nullptr;
|
void* externalAhb = nullptr;
|
||||||
// P8-C: A SHADER WROTE THIS STORE ON THIS SIDE since the R-11 staged copy (or, for
|
// P8-C: A SHADER WROTE THIS STORE ON THIS SIDE since the R-11 staged copy (or, for
|
||||||
@@ -1632,7 +1632,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Components per texel the frontend format's client data carries, for the three-channel
|
// Components per texel the frontend format's client data carries, for the three-channel
|
||||||
// formats that can be widened to a four-channel colour-renderable target; 0 for everything
|
// formats that can be widened to a four-channel color-renderable target; 0 for everything
|
||||||
// else. See PrepareChannelWidenedUpload.
|
// else. See PrepareChannelWidenedUpload.
|
||||||
Uint GetWidenableClientComponentCount(TextureInternalFormat format);
|
Uint GetWidenableClientComponentCount(TextureInternalFormat format);
|
||||||
|
|
||||||
@@ -1642,7 +1642,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Bool IsIntegerWidenableFormat(TextureInternalFormat format);
|
Bool IsIntegerWidenableFormat(TextureInternalFormat format);
|
||||||
|
|
||||||
// Repacks three-component client data as four components with an alpha of 1.0 in
|
// Repacks three-component client data as four components with an alpha of 1.0 in
|
||||||
// `uploadType`, for a format the backend widened to keep a colour attachment renderable.
|
// `uploadType`, for a format the backend widened to keep a color attachment renderable.
|
||||||
// Returns `data` untouched when no widening applies. Pure CPU and context-free so a unit
|
// Returns `data` untouched when no widening applies. Pure CPU and context-free so a unit
|
||||||
// test can exercise the exact packing the driver is handed; `widenedData` is the caller's
|
// test can exercise the exact packing the driver is handed; `widenedData` is the caller's
|
||||||
// scratch buffer and has to outlive the returned pointer.
|
// scratch buffer and has to outlive the returned pointer.
|
||||||
@@ -1921,7 +1921,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
SamplerParameters m_cacheSamplerParameters;
|
SamplerParameters m_cacheSamplerParameters;
|
||||||
UintVec2 m_cacheLodRange = {0, 1000};
|
UintVec2 m_cacheLodRange = {0, 1000};
|
||||||
// All three representations plus the form, because none of them alone identifies the
|
// All three representations plus the form, because none of them alone identifies the
|
||||||
// border colour the driver texture is holding: two integer borders can share one float
|
// border color the driver texture is holding: two integer borders can share one float
|
||||||
// (anything differing above 2^24), and a Float -> Int transition can leave every number
|
// (anything differing above 2^24), and a Float -> Int transition can leave every number
|
||||||
// unchanged while still needing a different driver entry point.
|
// unchanged while still needing a different driver entry point.
|
||||||
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
FloatVec4 m_cacheBorderColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
@@ -1975,7 +1975,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Hands back the whole RECORD rather than its Params, because the parameter push
|
// Hands back the whole RECORD rather than its Params, because the parameter push
|
||||||
// reads two things from beside them: Desc.InternalFormat, which decides the two
|
// reads two things from beside them: Desc.InternalFormat, which decides the two
|
||||||
// channel-widening swizzle compositions, and Params.BuiltinSampler, which is where
|
// channel-widening swizzle compositions, and Params.BuiltinSampler, which is where
|
||||||
// the border colour lives (it is sampler state, GL 4.6 table 23.18, and P4a does
|
// the border color lives (it is sampler state, GL 4.6 table 23.18, and P4a does
|
||||||
// not duplicate it onto MGPTextureParams).
|
// not duplicate it onto MGPTextureParams).
|
||||||
const MG_Pipe::MGPipeResourceRecord* ResolvePushedTextureParams(
|
const MG_Pipe::MGPipeResourceRecord* ResolvePushedTextureParams(
|
||||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||||
@@ -1994,7 +1994,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// m_syncedShapeParamsVersion) AND m_syncedContentVersion: the applier bumps it on
|
// m_syncedShapeParamsVersion) AND m_syncedContentVersion: the applier bumps it on
|
||||||
// every respecify and every sub-data it applies to this resource, which is exactly
|
// every respecify and every sub-data it applies to this resource, which is exactly
|
||||||
// the union those four covered, without the coarse "any texture's churn re-opens
|
// the union those four covered, without the coarse "any texture's churn re-opens
|
||||||
// every gate" behaviour the sampling-resolution generation had.
|
// every gate" behavior the sampling-resolution generation had.
|
||||||
Uint64 m_syncedResourceSerial = 0;
|
Uint64 m_syncedResourceSerial = 0;
|
||||||
// The record's ParamsSerial at the last SyncTextureParamsToBackend. Replaces
|
// The record's ParamsSerial at the last SyncTextureParamsToBackend. Replaces
|
||||||
// m_syncedTextureParamsVersion; MGPTextureParams::ForceResync replaces
|
// m_syncedTextureParamsVersion; MGPTextureParams::ForceResync replaces
|
||||||
@@ -2186,7 +2186,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
framebuffer, as a GL_COLOR_ATTACHMENTm enum. ES only accepts glDrawBuffers bufs[s] ==
|
framebuffer, as a GL_COLOR_ATTACHMENTm enum. ES only accepts glDrawBuffers bufs[s] ==
|
||||||
GL_COLOR_ATTACHMENTs, so a GL draw-buffer slot s naming attachment a forces a's image
|
GL_COLOR_ATTACHMENTs, so a GL draw-buffer slot s naming attachment a forces a's image
|
||||||
under backend slot s. This table is the single owner of that decision and is kept a
|
under backend slot s. This table is the single owner of that decision and is kept a
|
||||||
PERMUTATION of the backend colour slots: every other attachment keeps its identity
|
PERMUTATION of the backend color slots: every other attachment keeps its identity
|
||||||
slot when that slot survived, and is parked on the lowest free slot when it did not.
|
slot when that slot survived, and is parked on the lowest free slot when it did not.
|
||||||
Deriving the point per-query from the draw-buffer array instead handed the identity
|
Deriving the point per-query from the draw-buffer array instead handed the identity
|
||||||
point to any attachment that was not a draw buffer - i.e. exactly the point a
|
point to any attachment that was not a draw buffer - i.e. exactly the point a
|
||||||
@@ -2248,7 +2248,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// false accounts of one physical state: a composite framebuffer synced as DRAW in a
|
// false accounts of one physical state: a composite framebuffer synced as DRAW in a
|
||||||
// depth pre-pass detaches the points its other attachment state attaches, and the
|
// depth pre-pass detaches the points its other attachment state attaches, and the
|
||||||
// end-of-frame sync of that same record on the READ side then found its own slot
|
// end-of-frame sync of that same record on the READ side then found its own slot
|
||||||
// already stamped by an earlier identical sync, walked nothing, left the colour point
|
// already stamped by an earlier identical sync, walked nothing, left the color point
|
||||||
// detached, and the driver refused the following glBlitFramebuffer with
|
// detached, and the driver refused the following glBlitFramebuffer with
|
||||||
// INVALID_OPERATION. Keying on the object is what makes "this hash is applied" mean
|
// INVALID_OPERATION. Keying on the object is what makes "this hash is applied" mean
|
||||||
// "these points are on the driver now".
|
// "these points are on the driver now".
|
||||||
@@ -2305,7 +2305,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// describe that point at all (Color8..Color31, and the default framebuffer's FRONT/BACK
|
// describe that point at all (Color8..Color31, and the default framebuffer's FRONT/BACK
|
||||||
// tokens). MGPFramebufferState carries Color[8] + Depth + Stencil, which is every point
|
// tokens). MGPFramebufferState carries Color[8] + Depth + Stencil, which is every point
|
||||||
// a framebuffer can hold on the handle arm - D-C3 refuses bit 9 outright on a driver
|
// a framebuffer can hold on the handle arm - D-C3 refuses bit 9 outright on a driver
|
||||||
// reporting more than 8 colour attachments. P5e (fb) exports it: the twin's attachment
|
// reporting more than 8 color attachments. P5e (fb) exports it: the twin's attachment
|
||||||
// walk, the named blit's aspect plan and the detach walk all ask the same question of
|
// walk, the named blit's aspect plan and the detach walk all ask the same question of
|
||||||
// the same record, and a second copy of the Color/Depth/Stencil dispatch beside each of
|
// the same record, and a second copy of the Color/Depth/Stencil dispatch beside each of
|
||||||
// them is how one of them ends up describing a point differently from the others.
|
// them is how one of them ends up describing a point differently from the others.
|
||||||
@@ -2313,13 +2313,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
FramebufferAttachmentType point);
|
FramebufferAttachmentType point);
|
||||||
// True when the read buffer names a fixed-point (norm/snorm) attachment that the
|
// True when the read buffer names a fixed-point (norm/snorm) attachment that the
|
||||||
// backend actually stores in a floating-point format. GL clamps a read from a
|
// backend actually stores in a floating-point format. GL clamps a read from a
|
||||||
// fixed-point colour buffer to [0,1] (GL_CLAMP_READ_COLOR defaults to
|
// fixed-point color buffer to [0,1] (GL_CLAMP_READ_COLOR defaults to
|
||||||
// GL_FIXED_ONLY); the substituted float storage would not, so the readback path
|
// GL_FIXED_ONLY); the substituted float storage would not, so the readback path
|
||||||
// has to apply the clamp itself.
|
// has to apply the clamp itself.
|
||||||
Bool IsFixedPointFallbackReadAttachment();
|
Bool IsFixedPointFallbackReadAttachment();
|
||||||
|
|
||||||
// True when the read buffer names a three-channel attachment the backend actually stores
|
// True when the read buffer names a three-channel attachment the backend actually stores
|
||||||
// in a four-channel format (the colour-renderable widening). A format without alpha reads
|
// in a four-channel format (the color-renderable widening). A format without alpha reads
|
||||||
// back as 1.0, so the readback path has to overwrite the alpha the draw left behind -
|
// back as 1.0, so the readback path has to overwrite the alpha the draw left behind -
|
||||||
// unconditionally, since this is the format's own semantics rather than the
|
// unconditionally, since this is the format's own semantics rather than the
|
||||||
// GL_CLAMP_READ_COLOR rule the clamp above implements.
|
// GL_CLAMP_READ_COLOR rule the clamp above implements.
|
||||||
@@ -2337,19 +2337,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// driver where no interception is possible. So the stored alpha is kept at 1.0 instead:
|
// driver where no interception is possible. So the stored alpha is kept at 1.0 instead:
|
||||||
// a clear touching a widened buffer writes alpha 1.0, and every draw into it has its
|
// a clear touching a widened buffer writes alpha 1.0, and every draw into it has its
|
||||||
// alpha write mask forced off, so nothing can ever move it again. The application's own
|
// alpha write mask forced off, so nothing can ever move it again. The application's own
|
||||||
// colour mask is untouched - glGet(GL_COLOR_WRITEMASK) still reports what it set.
|
// color mask is untouched - glGet(GL_COLOR_WRITEMASK) still reports what it set.
|
||||||
extern Uint32 g_alphaWidenedDrawBufferMask;
|
extern Uint32 g_alphaWidenedDrawBufferMask;
|
||||||
|
|
||||||
// Bit i set = DRAW BUFFER i of the framebuffer bound as DRAW resolves to a colour
|
// Bit i set = DRAW BUFFER i of the framebuffer bound as DRAW resolves to a color
|
||||||
// attachment with an INTEGER format. Recomputed beside the mask above and for its sake:
|
// attachment with an INTEGER format. Recomputed beside the mask above and for its sake:
|
||||||
// glClearBufferfv on an integer colour buffer is GL_INVALID_OPERATION, so the
|
// glClearBufferfv on an integer color buffer is GL_INVALID_OPERATION, so the
|
||||||
// per-draw-buffer clear route the widening needs has to stand down when one is present.
|
// per-draw-buffer clear route the widening needs has to stand down when one is present.
|
||||||
// (glClear on an integer colour buffer is left undefined by ES in the first place, and
|
// (glClear on an integer color buffer is left undefined by ES in the first place, and
|
||||||
// an application that wants a defined answer has to call glClearBufferuiv/iv - which does
|
// an application that wants a defined answer has to call glClearBufferuiv/iv - which does
|
||||||
// carry the widened alpha substitution.)
|
// carry the widened alpha substitution.)
|
||||||
extern Uint32 g_integerColorDrawBufferMask;
|
extern Uint32 g_integerColorDrawBufferMask;
|
||||||
|
|
||||||
// The colour a clear has to hand the driver for one draw buffer: the application's value,
|
// The color a clear has to hand the driver for one draw buffer: the application's value,
|
||||||
// except that a widened attachment's alpha is replaced by the 1.0 its three-channel
|
// except that a widened attachment's alpha is replaced by the 1.0 its three-channel
|
||||||
// format implies. `one` is 1.0 encoded in the clear call's own component type - the
|
// format implies. `one` is 1.0 encoded in the clear call's own component type - the
|
||||||
// integer clears carry the integer 1, the float clear carries 1.0f.
|
// integer clears carry the integer 1, the float clear carries 1.0f.
|
||||||
@@ -2909,7 +2909,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// self-contained would produce a per-draw rebuild: the other eight inputs - the draw
|
// self-contained would produce a per-draw rebuild: the other eight inputs - the draw
|
||||||
// FBO's snorm/unorm clamp masks, the fragColor broadcast count, the storage-block
|
// FBO's snorm/unorm clamp masks, the fragColor broadcast count, the storage-block
|
||||||
// binding signature, the atomic-counter set, the live image formats and the patch
|
// binding signature, the atomic-counter set, the live image formats and the patch
|
||||||
// parameters - are all still specialised at the verb, from state this backend holds.
|
// parameters - are all still specialized at the verb, from state this backend holds.
|
||||||
// 0 means "never stamped", which is a guaranteed miss (applier serials start at 1).
|
// 0 means "never stamped", which is a guaranteed miss (applier serials start at 1).
|
||||||
Uint64 GetSyncedShaderCsoSerial() const { return m_syncedShaderCsoSerial; }
|
Uint64 GetSyncedShaderCsoSerial() const { return m_syncedShaderCsoSerial; }
|
||||||
// P5e (pg): the SECOND server-owned key, and it replaces GetImageUnitVersion() on
|
// P5e (pg): the SECOND server-owned key, and it replaces GetImageUnitVersion() on
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// (Ops_H_ImportExternal below). The twin holds its own reference, and every path that
|
// (Ops_H_ImportExternal below). The twin holds its own reference, and every path that
|
||||||
// ends the store - a respecify, a destroy, a re-import - deletes the GL id and then
|
// ends the store - a respecify, a destroy, a re-import - deletes the GL id and then
|
||||||
// RETIRES the reference here: a fence is inserted after the delete, and the reference is
|
// RETIRES the reference here: a fence is inserted after the delete, and the reference is
|
||||||
// released only once that fence has signalled, i.e. once every command that could still
|
// released only once that fence has signaled, i.e. once every command that could still
|
||||||
// read or write the pages has completed on this context's GPU. The client's own
|
// read or write the pages has completed on this context's GPU. The client's own
|
||||||
// reference ends independently (it releases on respecify/destroy); the pages live until
|
// reference ends independently (it releases on respecify/destroy); the pages live until
|
||||||
// the last of the two. No link watermark is involved (F-L2): the fence is this server's.
|
// the last of the two. No link watermark is involved (F-L2): the fence is this server's.
|
||||||
@@ -1046,8 +1046,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// sees the reconciled shadow on return, exactly as before.
|
// sees the reconciled shadow on return, exactly as before.
|
||||||
//
|
//
|
||||||
// THE ORDER FROM HERE IS A CORRECTNESS RULE, NOT A PREFERENCE
|
// THE ORDER FROM HERE IS A CORRECTNESS RULE, NOT A PREFERENCE
|
||||||
// (ARCHITECTURE.md 8.2: "写回的 epoch bump 必须在任何后续读该 handle 的命令之前被
|
// (ARCHITECTURE.md 8.2: "the writeback's epoch bump must be applied by the server before any
|
||||||
// server 应用;反向通道需要与正向通道相同的有序保证"):
|
// later command that reads that handle; the reverse channel needs the same ordering guarantees as the
|
||||||
|
// forward channel"):
|
||||||
// 1. writeback - the client's shadow takes the bytes,
|
// 1. writeback - the client's shadow takes the bytes,
|
||||||
// 2. unmap - the read mapping goes away,
|
// 2. unmap - the read mapping goes away,
|
||||||
// 3. serial stamp- syncedChangeSerial catches up with the record, so the next
|
// 3. serial stamp- syncedChangeSerial catches up with the record, so the next
|
||||||
@@ -1900,7 +1901,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The seventh slot table. A process-lifetime global, like the other six, so it links
|
// The seventh slot table. A process-lifetime global, like the other six, so it links
|
||||||
// itself into its own holder list from its own constructor with no initialisation
|
// itself into its own holder list from its own constructor with no initialization
|
||||||
// order question to answer (SlotTables.h).
|
// order question to answer (SlotTables.h).
|
||||||
BackendBufferResourceTable g_backendBufferResources;
|
BackendBufferResourceTable g_backendBufferResources;
|
||||||
|
|
||||||
@@ -2112,7 +2113,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||||
// P11 B2: the T0 half of the deferred-release drain, run right after it at both sync
|
// P11 B2: the T0 half of the deferred-release drain, run right after it at both sync
|
||||||
// points (ProcessDeferredBufferReleases itself moves verbatim, G5). Retired imports whose
|
// points (ProcessDeferredBufferReleases itself moves verbatim, G5). Retired imports whose
|
||||||
// fence signalled let go of their AHardwareBuffer; a deferred T0 destroy is retired once
|
// fence signaled let go of their AHardwareBuffer; a deferred T0 destroy is retired once
|
||||||
// the drain deleted its id (the fence then follows the delete) or its context is gone.
|
// the drain deleted its id (the fence then follows the delete) or its context is gone.
|
||||||
void ProcessDeferredT0Retires() {
|
void ProcessDeferredT0Retires() {
|
||||||
if (!g_t0Retired.empty()) SweepT0Retired(false);
|
if (!g_t0Retired.empty()) SweepT0Retired(false);
|
||||||
@@ -2309,7 +2310,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const SizeT poolSize = ResourceWidthOf(res);
|
const SizeT poolSize = ResourceWidthOf(res);
|
||||||
// The pool DECISION is the legacy one, unchanged: extent and residence only.
|
// The pool DECISION is the legacy one, unchanged: extent and residence only.
|
||||||
// An earlier cut added "and a shadow base was recorded", which silently stopped
|
// An earlier cut added "and a shadow base was recorded", which silently stopped
|
||||||
// a buffer recycling pool ids - a change to D-F's pool behaviour, not to "the
|
// a buffer recycling pool ids - a change to D-F's pool behavior, not to "the
|
||||||
// source of bytes" the conversion is allowed to move, and one that moves
|
// source of bytes" the conversion is allowed to move, and one that moves
|
||||||
// AcquireFromPool call counts StreamedArenaScenario observes.
|
// AcquireFromPool call counts StreamedArenaScenario observes.
|
||||||
const Uint reused = (poolSize > 0 && !resource->persistentMapped) ? AcquireFromPool(poolSize) : 0;
|
const Uint reused = (poolSize > 0 && !resource->persistentMapped) ? AcquireFromPool(poolSize) : 0;
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// re-issued is invalidated too - the attachment versions below, and under
|
// re-issued is invalidated too - the attachment versions below, and under
|
||||||
// MOBILEGL_PIPE_PUSH the record memos stamped at the end of this function - so the
|
// MOBILEGL_PIPE_PUSH the record memos stamped at the end of this function - so the
|
||||||
// next sync re-attaches all non-empty attachments at their identity points AND
|
// next sync re-attaches all non-empty attachments at their identity points AND
|
||||||
// (see SyncToBackend's attachment loop) detaches any colour point whose frontend owner
|
// (see SyncToBackend's attachment loop) detaches any color point whose frontend owner
|
||||||
// is empty. Without that detach a stale image would survive under a point the table now
|
// is empty. Without that detach a stale image would survive under a point the table now
|
||||||
// claims for a different, empty attachment.
|
// claims for a different, empty attachment.
|
||||||
for (Uint i = 0; i < MAX_COLOR_ATTACHMENT_SLOTS; ++i) {
|
for (Uint i = 0; i < MAX_COLOR_ATTACHMENT_SLOTS; ++i) {
|
||||||
@@ -250,7 +250,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// kMGPipeSurfaceNoTextureTarget on a texture point is a seam defect - refused loudly and
|
// kMGPipeSurfaceNoTextureTarget on a texture point is a seam defect - refused loudly and
|
||||||
// answered false, never guessed. False is the safe direction for all four: the mask
|
// answered false, never guessed. False is the safe direction for all four: the mask
|
||||||
// turns an emulation ON, and an emulation that does not run leaves the driver's own
|
// turns an emulation ON, and an emulation that does not run leaves the driver's own
|
||||||
// (correct-for-the-real-format) behaviour, while one that runs on the wrong buffer
|
// (correct-for-the-real-format) behavior, while one that runs on the wrong buffer
|
||||||
// clamps or overwrites texels the application wrote.
|
// clamps or overwrites texels the application wrote.
|
||||||
static Bool PushedSurfaceTextureTarget(const MG_Pipe::MGPSurface& surface, TextureTarget* out) {
|
static Bool PushedSurfaceTextureTarget(const MG_Pipe::MGPSurface& surface, TextureTarget* out) {
|
||||||
if (surface.TextureTarget == MG_Pipe::kMGPipeSurfaceNoTextureTarget) {
|
if (surface.TextureTarget == MG_Pipe::kMGPipeSurfaceNoTextureTarget) {
|
||||||
@@ -314,7 +314,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The record's surface for an attachment POINT, or null when this record does not
|
// The record's surface for an attachment POINT, or null when this record does not
|
||||||
// describe that point at all. MGPFramebufferState carries Color[8] + Depth + Stencil
|
// describe that point at all. MGPFramebufferState carries Color[8] + Depth + Stencil
|
||||||
// (D-C1), which is every point a framebuffer can hold on the handle arm: D-C3 refuses
|
// (D-C1), which is every point a framebuffer can hold on the handle arm: D-C3 refuses
|
||||||
// bit 9 outright on a driver reporting more than 8 colour attachments, and the
|
// bit 9 outright on a driver reporting more than 8 color attachments, and the
|
||||||
// FRONT/BACK points belong to the DEFAULT framebuffer, which has no twin at all.
|
// FRONT/BACK points belong to the DEFAULT framebuffer, which has no twin at all.
|
||||||
const MG_Pipe::MGPSurface* PushedSurfaceForAttachment(const MG_Pipe::MGPFramebufferState& record,
|
const MG_Pipe::MGPSurface* PushedSurfaceForAttachment(const MG_Pipe::MGPFramebufferState& record,
|
||||||
FramebufferAttachmentType point) {
|
FramebufferAttachmentType point) {
|
||||||
@@ -465,7 +465,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// an object the apply thread was handed.
|
// an object the apply thread was handed.
|
||||||
//
|
//
|
||||||
// P5e (fix1, ID-81): arm-selected for the texture arm's reason, and here it is a
|
// P5e (fix1, ID-81): arm-selected for the texture arm's reason, and here it is a
|
||||||
// BEHAVIOUR difference even though the by-handle body dereferences nothing: the
|
// BEHAVIOR difference even though the by-handle body dereferences nothing: the
|
||||||
// object form reports a refused allocation to the application through the live
|
// object form reports a refused allocation to the application through the live
|
||||||
// GLContext (RecordError) and the by-handle form deliberately does not, because
|
// GLContext (RecordError) and the by-handle form deliberately does not, because
|
||||||
// under a transport there is no application on this side to report it to. On the
|
// under a transport there is no application on this side to report it to. On the
|
||||||
@@ -483,7 +483,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The read attachment's storage carries an alpha channel its frontend format does not
|
// The read attachment's storage carries an alpha channel its frontend format does not
|
||||||
// (the three-channel colour-renderable widening). GL answers such a read with 1.0, but
|
// (the three-channel color-renderable widening). GL answers such a read with 1.0, but
|
||||||
// the storage holds whatever the draw wrote there, so the readback has to overwrite it.
|
// the storage holds whatever the draw wrote there, so the readback has to overwrite it.
|
||||||
Bool IsAlphaWidenedFallbackReadAttachment() {
|
Bool IsAlphaWidenedFallbackReadAttachment() {
|
||||||
const auto* record = MG_Pipe::MGPipeApplier().ReadFramebuffer();
|
const auto* record = MG_Pipe::MGPipeApplier().ReadFramebuffer();
|
||||||
@@ -552,7 +552,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
void BackendFramebufferObject::ApplyReadBufferFromRecord(const MG_Pipe::MGPFramebufferState& record,
|
void BackendFramebufferObject::ApplyReadBufferFromRecord(const MG_Pipe::MGPFramebufferState& record,
|
||||||
Uint glNameForDiag) {
|
Uint glNameForDiag) {
|
||||||
// D-C1 makes the NULL Res the spelling of "no attachment" and c0c's
|
// D-C1 makes the NULL Res the spelling of "no attachment" and c0c's
|
||||||
// kMGPipeSurfaceKindNone makes Kind agree with it on a zero-initialised record.
|
// kMGPipeSurfaceKindNone makes Kind agree with it on a zero-initialized record.
|
||||||
// Res stays the test - it is the one D-C1 fixes - and Kind is CROSS-CHECKED
|
// Res stays the test - it is the one D-C1 fixes - and Kind is CROSS-CHECKED
|
||||||
// rather than consulted: the two are one statement the emitter has to make
|
// rather than consulted: the two are one statement the emitter has to make
|
||||||
// twice, and a record where they disagree is a seam defect, not an empty point.
|
// twice, and a record where they disagree is a seam defect, not an empty point.
|
||||||
@@ -569,7 +569,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
FramebufferAttachmentType pushedReadBuf = FramebufferAttachmentType::None;
|
FramebufferAttachmentType pushedReadBuf = FramebufferAttachmentType::None;
|
||||||
if (!readSurfaceEmpty) {
|
if (!readSurfaceEmpty) {
|
||||||
// EVERY FIELD THAT IDENTIFIES THE IMAGE, not the three v1 compared (m-4).
|
// EVERY FIELD THAT IDENTIFIES THE IMAGE, not the three v1 compared (m-4).
|
||||||
// The same image legally sits at two colour points - a layered attachment of
|
// The same image legally sits at two color points - a layered attachment of
|
||||||
// one array and a single slice of it are different surfaces of one Res - so a
|
// one array and a single slice of it are different surfaces of one Res - so a
|
||||||
// partial comparison resolves to the lower index and the refusal branch below
|
// partial comparison resolves to the lower index and the refusal branch below
|
||||||
// ("refusing to guess") would then be doing part of the guessing itself.
|
// ("refusing to guess") would then be doing part of the guessing itself.
|
||||||
@@ -590,7 +590,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
if (!matched) {
|
if (!matched) {
|
||||||
MGLOG_E_ONCE("MGPipe: framebuffer %u's resolved read surface {%u, %u} matches no "
|
MGLOG_E_ONCE("MGPipe: framebuffer %u's resolved read surface {%u, %u} matches no "
|
||||||
"colour attachment of its own record - refusing to guess a read "
|
"color attachment of its own record - refusing to guess a read "
|
||||||
"buffer",
|
"buffer",
|
||||||
glNameForDiag, record.ReadSurface.Res.Slot, record.ReadSurface.Res.Gen);
|
glNameForDiag, record.ReadSurface.Res.Slot, record.ReadSurface.Res.Gen);
|
||||||
return;
|
return;
|
||||||
@@ -659,7 +659,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// fire the table would disagree with the glDrawBuffers the caller already issued,
|
// fire the table would disagree with the glDrawBuffers the caller already issued,
|
||||||
// which is the exact non-injectivity this table exists to remove.
|
// which is the exact non-injectivity this table exists to remove.
|
||||||
MOBILEGL_ASSERT(a < slotCount && !assigned[a],
|
MOBILEGL_ASSERT(a < slotCount && !assigned[a],
|
||||||
"Draw buffer %u names colour attachment %u which is out of range or duplicated.", s, a);
|
"Draw buffer %u names color attachment %u which is out of range or duplicated.", s, a);
|
||||||
if (a >= slotCount || assigned[a]) {
|
if (a >= slotCount || assigned[a]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -890,7 +890,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// 3. The attachments. Three gates, and the key is the object's rather than the
|
// 3. The attachments. Three gates, and the key is the object's rather than the
|
||||||
// binding's: idGenerationMoved ("I re-minted a driver id, so a point may hold a
|
// binding's: idGenerationMoved ("I re-minted a driver id, so a point may hold a
|
||||||
// dead one"), attachmentPointsMoved ("the colour permutation moved, so a point
|
// dead one"), attachmentPointsMoved ("the color permutation moved, so a point
|
||||||
// whose record did not change still has to be re-issued") and the record hash.
|
// whose record did not change still has to be re-issued") and the record hash.
|
||||||
// NOT m_syncedRecordHashes: the per-target array is the object arm's re-arm
|
// NOT m_syncedRecordHashes: the per-target array is the object arm's re-arm
|
||||||
// trigger, and the points written below belong to the driver FBO rather than to
|
// trigger, and the points written below belong to the driver FBO rather than to
|
||||||
@@ -910,7 +910,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const Bool empty =
|
const Bool empty =
|
||||||
surface.Kind == MG_Pipe::kMGPipeSurfaceKindNone || MG_Pipe::MGPipeHandleIsNull(surface.Res);
|
surface.Kind == MG_Pipe::kMGPipeSurfaceKindNone || MG_Pipe::MGPipeHandleIsNull(surface.Res);
|
||||||
// The detach that keeps m_backendColorSlots a permutation of the PHYSICAL
|
// The detach that keeps m_backendColorSlots a permutation of the PHYSICAL
|
||||||
// layout: a colour point whose record says empty must not keep the previous
|
// layout: a color point whose record says empty must not keep the previous
|
||||||
// owner's image, or glReadBuffer returns it. Bounded by the driver's cap,
|
// owner's image, or glReadBuffer returns it. Bounded by the driver's cap,
|
||||||
// because GL_COLOR_ATTACHMENTn above it is INVALID_ENUM.
|
// because GL_COLOR_ATTACHMENTn above it is INVALID_ENUM.
|
||||||
if (isColorPoint && empty) {
|
if (isColorPoint && empty) {
|
||||||
@@ -979,12 +979,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const {
|
GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const {
|
||||||
// Only colour attachments are ever relocated; depth/stencil, the default framebuffer's
|
// Only color attachments are ever relocated; depth/stencil, the default framebuffer's
|
||||||
// FRONT/BACK names and None map straight through.
|
// FRONT/BACK names and None map straight through.
|
||||||
if (frontendAtt < FramebufferAttachmentType::Color0 || frontendAtt > FramebufferAttachmentType::Color31) {
|
if (frontendAtt < FramebufferAttachmentType::Color0 || frontendAtt > FramebufferAttachmentType::Color31) {
|
||||||
return MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendAtt);
|
return MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendAtt);
|
||||||
}
|
}
|
||||||
// The table is a permutation of the backend colour points, so this is the one point that
|
// The table is a permutation of the backend color points, so this is the one point that
|
||||||
// owns this attachment. Searching the draw-buffer array instead returned the identity
|
// owns this attachment. Searching the draw-buffer array instead returned the identity
|
||||||
// point for every attachment that was not a draw buffer - which is exactly the point a
|
// point for every attachment that was not a draw buffer - which is exactly the point a
|
||||||
// relocated draw buffer had just taken over, so COLOR_ATTACHMENT0 read back the image of
|
// relocated draw buffer had just taken over, so COLOR_ATTACHMENT0 read back the image of
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// The four hostBytes sites read the same in both builds. The non-split expansion is the
|
// The four hostBytes sites read the same in both builds. The non-split expansion is the
|
||||||
// ORIGINAL EXPRESSION, character for character - `raw - offset` - so a push or verify build
|
// ORIGINAL EXPRESSION, character for character - `raw - offset` - so a push or verify build
|
||||||
// compiles exactly what it compiled before R-11 and the split arm is the only new behaviour.
|
// compiles exactly what it compiled before R-11 and the split arm is the only new behavior.
|
||||||
#define MGL_SERVER_STAGED_ADOPT(res, width, bytes, offset, size) \
|
#define MGL_SERVER_STAGED_ADOPT(res, width, bytes, offset, size) \
|
||||||
ServerStaged().Adopt(&(res), (width), (bytes), (offset), (size))
|
ServerStaged().Adopt(&(res), (width), (bytes), (offset), (size))
|
||||||
#define MGL_SERVER_STAGED_REQUIRE_PENDING(res, base, frontendSize, site) \
|
#define MGL_SERVER_STAGED_REQUIRE_PENDING(res, base, frontendSize, site) \
|
||||||
@@ -476,7 +476,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// One shape for all five, so a kind cannot grow a different liveness rule than its
|
// One shape for all five, so a kind cannot grow a different liveness rule than its
|
||||||
// neighbours: index the applier's own dense table, refuse a slot it has not grown to,
|
// neighbors: index the applier's own dense table, refuse a slot it has not grown to,
|
||||||
// refuse a record that is not Live, and refuse a generation that has moved on under
|
// refuse a record that is not Live, and refuse a generation that has moved on under
|
||||||
// the caller. The last of the three is the one that matters: a stale handle resolving
|
// the caller. The last of the three is the one that matters: a stale handle resolving
|
||||||
// to its successor's record is how a twin ends up describing another object's storage.
|
// to its successor's record is how a twin ends up describing another object's storage.
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// every draw of every program with an override would rebuild. Taking the client's number
|
// every draw of every program with an override would rebuild. Taking the client's number
|
||||||
// verbatim removes that coupling: there is one authority, and the twin's stamp and the
|
// verbatim removes that coupling: there is one authority, and the twin's stamp and the
|
||||||
// clean clause read the same field. The monolith arm's source carries the answer of the
|
// clean clause read the same field. The monolith arm's source carries the answer of the
|
||||||
// function this replaces, computed from the frontend map, so its behaviour is unchanged.
|
// function this replaces, computed from the frontend map, so its behavior is unchanged.
|
||||||
Uint64 ComputeShaderStorageBlockBindingSignature(const ProgramBuildSource& src) {
|
Uint64 ComputeShaderStorageBlockBindingSignature(const ProgramBuildSource& src) {
|
||||||
return src.StorageOverrideSignature;
|
return src.StorageOverrideSignature;
|
||||||
}
|
}
|
||||||
@@ -1022,7 +1022,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// GL 4.6 core table 23.53 requires GL_MAX_SAMPLES >= 4, so every multisample
|
// GL 4.6 core table 23.53 requires GL_MAX_SAMPLES >= 4, so every multisample
|
||||||
// ceiling MobileGL advertises is floored to 4 no matter what the ES driver
|
// ceiling MobileGL advertises is floored to 4 no matter what the ES driver
|
||||||
// reports - but the realised allocation cannot be, and
|
// reports - but the realized allocation cannot be, and
|
||||||
// ClampSamplesToBackendSupport quietly gives an integer or depth multisample
|
// ClampSamplesToBackendSupport quietly gives an integer or depth multisample
|
||||||
// texture the ONE sample Adreno and Mali actually support for it. A shader
|
// texture the ONE sample Adreno and Mali actually support for it. A shader
|
||||||
// written against the advertised ceiling then fetches a sample that storage does
|
// written against the advertised ceiling then fetches a sample that storage does
|
||||||
@@ -1051,7 +1051,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
*effectiveSpirv, splitArrayInputSpirv, enableSpirvValidation) &&
|
*effectiveSpirv, splitArrayInputSpirv, enableSpirvValidation) &&
|
||||||
!splitArrayInputSpirv.empty() && splitArrayInputSpirv != *effectiveSpirv) {
|
!splitArrayInputSpirv.empty() && splitArrayInputSpirv != *effectiveSpirv) {
|
||||||
// Only when the pass ACTUALLY split something: the optimizer hands back a
|
// Only when the pass ACTUALLY split something: the optimizer hands back a
|
||||||
// re-serialised copy either way, and that round trip is not free - it cost the
|
// re-serialized copy either way, and that round trip is not free - it cost the
|
||||||
// minecraft-1.21.1-neoforge-create-indirect-in-world-align1024 retrace 0.15 SSIM.
|
// minecraft-1.21.1-neoforge-create-indirect-in-world-align1024 retrace 0.15 SSIM.
|
||||||
effectiveSpirv = &splitArrayInputSpirv;
|
effectiveSpirv = &splitArrayInputSpirv;
|
||||||
}
|
}
|
||||||
@@ -1095,11 +1095,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Left outside, a second program sharing this stage's key would be served ESSL
|
// Left outside, a second program sharing this stage's key would be served ESSL
|
||||||
// with the blocks un-renamed and the repair would silently stop working - the
|
// with the blocks un-renamed and the repair would silently stop working - the
|
||||||
// same trap SetAtomicCounterBlockBindings sets one screen down.
|
// same trap SetAtomicCounterBlockBindings sets one screen down.
|
||||||
// * AT THIS POSITION, because moving a SPIR-V pass in a chain is a behavioural
|
// * AT THIS POSITION, because moving a SPIR-V pass in a chain is a behavioral
|
||||||
// change, and this one arrived device-verified on Mali. Hoisting it above the
|
// change, and this one arrived device-verified on Mali. Hoisting it above the
|
||||||
// cache probe instead would have needed no key material at all (the rename would
|
// cache probe instead would have needed no key material at all (the rename would
|
||||||
// already be in the module bytes the key hashes) and was rejected for that
|
// already be in the module bytes the key hashes) and was rejected for that
|
||||||
// reason: it reorders the chain, and it would re-serialise the module on every
|
// reason: it reorders the chain, and it would re-serialize the module on every
|
||||||
// build including the ones the memo is there to make free.
|
// build including the ones the memo is there to make free.
|
||||||
// Its two rename maps are therefore KEY MATERIAL - see the caller.
|
// Its two rename maps are therefore KEY MATERIAL - see the caller.
|
||||||
Vector<unsigned int> uniquifiedIoBlockSpirv;
|
Vector<unsigned int> uniquifiedIoBlockSpirv;
|
||||||
@@ -1333,7 +1333,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The caller arms the two directions; both are false unless the driver POST
|
// The caller arms the two directions; both are false unless the driver POST
|
||||||
// measured the defect AND this program has a stage that can hit it. Adopted only
|
// measured the defect AND this program has a stage that can hit it. Adopted only
|
||||||
// when this stage really had a located block, for the reason the array-input split
|
// when this stage really had a located block, for the reason the array-input split
|
||||||
// documents: the optimizer hands back a re-serialised copy either way.
|
// documents: the optimizer hands back a re-serialized copy either way.
|
||||||
//
|
//
|
||||||
// LAST IN THE CHAIN, and that position is load-bearing. Vulkan SPIR-V REQUIRES a
|
// LAST IN THE CHAIN, and that position is load-bearing. Vulkan SPIR-V REQUIRES a
|
||||||
// Location on every user-defined Input/Output variable
|
// Location on every user-defined Input/Output variable
|
||||||
@@ -1385,7 +1385,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// ES fixes a storage block's binding at link from its layout(binding=) qualifier
|
// ES fixes a storage block's binding at link from its layout(binding=) qualifier
|
||||||
// and has no glShaderStorageBlockBinding to move it afterwards, so a rebinding
|
// and has no glShaderStorageBlockBinding to move it afterwards, so a rebinding
|
||||||
// can only be honoured by printing it INTO the qualifier. Rewriting the Binding
|
// can only be honored by printing it INTO the qualifier. Rewriting the Binding
|
||||||
// decoration before SPIRV-Cross emits is what does that; RemoveLayoutBinding
|
// decoration before SPIRV-Cross emits is what does that; RemoveLayoutBinding
|
||||||
// then deliberately preserves the qualifier for `buffer` declarations.
|
// then deliberately preserves the qualifier for `buffer` declarations.
|
||||||
if (!storageBlockBindingOverrides.empty()) { // empty for almost every program
|
if (!storageBlockBindingOverrides.empty()) { // empty for almost every program
|
||||||
@@ -1516,12 +1516,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mirrored from the neighbours rather than fixed: whether SPIRV-Cross redeclares
|
// Mirrored from the neighbors rather than fixed: whether SPIRV-Cross redeclares
|
||||||
// gl_PerVertex, and with which members, depends on what the application's shaders
|
// gl_PerVertex, and with which members, depends on what the application's shaders
|
||||||
// touched, and a synthesized stage that redeclares a DIFFERENT shape than the stage
|
// touched, and a synthesized stage that redeclares a DIFFERENT shape than the stage
|
||||||
// it feeds is an ES link error against a program with no other problem. gl_in copies
|
// it feeds is an ES link error against a program with no other problem. gl_in copies
|
||||||
// the vertex stage's OUT block (that is what arrives) and gl_out the evaluation
|
// the vertex stage's OUT block (that is what arrives) and gl_out the evaluation
|
||||||
// stage's IN block (that is what is expected). A neighbour that redeclared nothing
|
// stage's IN block (that is what is expected). A neighbor that redeclared nothing
|
||||||
// yields an empty list, which leaves the driver's own built-in declaration in place -
|
// yields an empty list, which leaves the driver's own built-in declaration in place -
|
||||||
// which is exactly what matching it requires.
|
// which is exactly what matching it requires.
|
||||||
const String inMembers = ExtractPerVertexBlockMembers(vertexStageEssl, /*input=*/false).value_or(String());
|
const String inMembers = ExtractPerVertexBlockMembers(vertexStageEssl, /*input=*/false).value_or(String());
|
||||||
@@ -1531,7 +1531,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
String source =
|
String source =
|
||||||
BuildPassthroughTessControlEssl(ResolveBackendEsslVersion(), patchVertices, inMembers, outMembers,
|
BuildPassthroughTessControlEssl(ResolveBackendEsslVersion(), patchVertices, inMembers, outMembers,
|
||||||
m_passthroughTessControlOuterLevel, m_passthroughTessControlInnerLevel);
|
m_passthroughTessControlOuterLevel, m_passthroughTessControlInnerLevel);
|
||||||
// The mirrored member lists can carry gl_PointSize - the neighbour stage declared it,
|
// The mirrored member lists can carry gl_PointSize - the neighbor stage declared it,
|
||||||
// so matching it is the whole point - and a redeclaration is exactly as illegal as a
|
// so matching it is the whole point - and a redeclaration is exactly as illegal as a
|
||||||
// reference in ESSL without the extension. Same directive, same never-speculative
|
// reference in ESSL without the extension. Same directive, same never-speculative
|
||||||
// rule as the per-stage loop; a driver with neither spelling gets nothing added and
|
// rule as the per-stage loop; a driver with neither spelling gets nothing added and
|
||||||
@@ -1543,7 +1543,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
: nullptr;
|
: nullptr;
|
||||||
source = RequestPointSizeExtension(Move(source), passthroughPointSizeExtension);
|
source = RequestPointSizeExtension(Move(source), passthroughPointSizeExtension);
|
||||||
// Same for gl_ClipDistance/gl_CullDistance mirrored out of a vertex stage that
|
// Same for gl_ClipDistance/gl_CullDistance mirrored out of a vertex stage that
|
||||||
// writes them: the neighbour could only compile with the extension, so it exists.
|
// writes them: the neighbor could only compile with the extension, so it exists.
|
||||||
source = RequestClipCullDistanceExtension(Move(source));
|
source = RequestClipCullDistanceExtension(Move(source));
|
||||||
|
|
||||||
const GLuint backendShaderId = g_GLESFuncs.glCreateShader(GL_TESS_CONTROL_SHADER);
|
const GLuint backendShaderId = g_GLESFuncs.glCreateShader(GL_TESS_CONTROL_SHADER);
|
||||||
@@ -1608,7 +1608,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_frontendProgramId = src.GetExternalIndex();
|
m_frontendProgramId = src.GetExternalIndex();
|
||||||
|
|
||||||
// GetSpirvStatus() as well as GetLinkStatus(): a program whose phase-B job was
|
// GetSpirvStatus() as well as GetLinkStatus(): a program whose phase-B job was
|
||||||
// cancelled (teardown) or whose optimizer run failed is fully linked and fully
|
// canceled (teardown) or whose optimizer run failed is fully linked and fully
|
||||||
// queryable, but has no SPIR-V to build a driver program out of. GL cannot retract
|
// queryable, but has no SPIR-V to build a driver program out of. GL cannot retract
|
||||||
// a LINK_STATUS it already reported true, so "linked but not drawable" is the
|
// a LINK_STATUS it already reported true, so "linked but not drawable" is the
|
||||||
// answer, and this is where the ES backend expresses it.
|
// answer, and this is where the ES backend expresses it.
|
||||||
@@ -1773,7 +1773,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// The repair is a rename keyed on the PRODUCING stage, planned here and applied
|
// The repair is a rename keyed on the PRODUCING stage, planned here and applied
|
||||||
// per stage below so a producer and its consumer keep naming the same block.
|
// per stage below so a producer and its consumer keep naming the same block.
|
||||||
// Gated twice over, because a re-serialised module is not free (it cost the
|
// Gated twice over, because a re-serialized module is not free (it cost the
|
||||||
// create-indirect retrace 0.15 SSIM the first time the array-input split missed
|
// create-indirect retrace 0.15 SSIM the first time the array-input split missed
|
||||||
// its gate; the case is now
|
// its gate; the case is now
|
||||||
// minecraft-1.21.1-neoforge-create-indirect-in-world-align1024): only a tessellation
|
// minecraft-1.21.1-neoforge-create-indirect-in-world-align1024): only a tessellation
|
||||||
@@ -1890,7 +1890,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// an output nothing can read. That is not merely useless: in a separable program
|
// an output nothing can read. That is not merely useless: in a separable program
|
||||||
// pipeline the fragment stage lives in a DIFFERENT program, which never saw this
|
// pipeline the fragment stage lives in a DIFFERENT program, which never saw this
|
||||||
// build and cannot be given a gate, so promoting there would hang an unmatched
|
// build and cannot be given a gate, so promoting there would hang an unmatched
|
||||||
// varying off a program to buy nothing. Both cases keep the pre-emulation behaviour,
|
// varying off a program to buy nothing. Both cases keep the pre-emulation behavior,
|
||||||
// which is what a program with no fragment stage had anyway.
|
// which is what a program with no fragment stage had anyway.
|
||||||
const Bool programHasFragmentStage =
|
const Bool programHasFragmentStage =
|
||||||
std::find(linkedStages.begin(), linkedStages.end(), ShaderStage::Fragment) != linkedStages.end();
|
std::find(linkedStages.begin(), linkedStages.end(), ShaderStage::Fragment) != linkedStages.end();
|
||||||
@@ -1974,7 +1974,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// KEYING ON THE RESOLVED MAPS rather than on what they were derived from
|
// KEYING ON THE RESOLVED MAPS rather than on what they were derived from
|
||||||
// (collidingIoBlockNames, declaredIoBlockNames, stagePipelineIndices, this
|
// (collidingIoBlockNames, declaredIoBlockNames, stagePipelineIndices, this
|
||||||
// stage's index) is deliberate: the maps ARE the pass's arguments, so they are
|
// stage's index) is deliberate: the maps ARE the pass's arguments, so they are
|
||||||
// exactly as fine as the pass's behaviour and no finer. Two programs whose
|
// exactly as fine as the pass's behavior and no finer. Two programs whose
|
||||||
// collision plans differ but whose maps for THIS stage come out identical really
|
// collision plans differ but whose maps for THIS stage come out identical really
|
||||||
// do produce the same ESSL and should share the entry.
|
// do produce the same ESSL and should share the entry.
|
||||||
//
|
//
|
||||||
@@ -2225,7 +2225,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// * AFTER RebindImageUniformsToFrontendUnits, so the binding it copies onto
|
// * AFTER RebindImageUniformsToFrontendUnits, so the binding it copies onto
|
||||||
// both halves of a split image is already the frontend texture unit (and so
|
// both halves of a split image is already the frontend texture unit (and so
|
||||||
// that pass never has to reason about the alias it introduces);
|
// that pass never has to reason about the alias it introduces);
|
||||||
// * BEFORE RemoveLayoutBinding, whose keepBindingRegex recognises an image
|
// * BEFORE RemoveLayoutBinding, whose keepBindingRegex recognizes an image
|
||||||
// declaration and preserves its binding - an image unit cannot be set from
|
// declaration and preserves its binding - an image unit cannot be set from
|
||||||
// the API in ES, so the qualifier is the only binding mechanism there is,
|
// the API in ES, so the qualifier is the only binding mechanism there is,
|
||||||
// and both halves of the pair have to still be carrying theirs when it runs.
|
// and both halves of the pair have to still be carrying theirs when it runs.
|
||||||
@@ -2639,7 +2639,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// arm - and building from an empty reflection would produce a program with no
|
// arm - and building from an empty reflection would produce a program with no
|
||||||
// uniforms and no modules, i.e. a black screen with no marker anywhere. The
|
// uniforms and no modules, i.e. a black screen with no marker anywhere. The
|
||||||
// create's own trip wire already refuses a record that declares no blobs AND
|
// create's own trip wire already refuses a record that declares no blobs AND
|
||||||
// carries no artefacts (PipeApply.cpp); this is the same statement one level later,
|
// carries no artifacts (PipeApply.cpp); this is the same statement one level later,
|
||||||
// where the twin can name the handle.
|
// where the twin can name the handle.
|
||||||
if (!record->Archive) {
|
if (!record->Archive) {
|
||||||
MGLOG_E_ONCE("MGPipe: shader CSO {%u, %u} carries no server-owned archive; its "
|
MGLOG_E_ONCE("MGPipe: shader CSO {%u, %u} carries no server-owned archive; its "
|
||||||
@@ -2668,7 +2668,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// one location per ELEMENT, so a caller walking locations sees the same name
|
// one location per ELEMENT, so a caller walking locations sees the same name
|
||||||
// repeatedly; this turns it back into "goku[k]". Anything that is not an array
|
// repeatedly; this turns it back into "goku[k]". Anything that is not an array
|
||||||
// (or whose base location cannot be resolved) comes back unchanged, so the only
|
// (or whose base location cannot be resolved) comes back unchanged, so the only
|
||||||
// behaviour that moves is the array case.
|
// behavior that moves is the array case.
|
||||||
String SubscriptUniformNameForElement(const ProgramBuildSource& program, const String& name,
|
String SubscriptUniformNameForElement(const ProgramBuildSource& program, const String& name,
|
||||||
Uint location) {
|
Uint location) {
|
||||||
if (name.size() < 3 || name.compare(name.size() - 3, 3, "[0]") != 0) return name;
|
if (name.size() < 3 || name.compare(name.size() - 3, 3, "[0]") != 0) return name;
|
||||||
@@ -2794,7 +2794,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
if (!m_backendProgramUsable) {
|
if (!m_backendProgramUsable) {
|
||||||
// Every draw made with this program renders nothing and raises no GL error, so
|
// Every draw made with this program renders nothing and raises no GL error, so
|
||||||
// without this line the only symptom is a framebuffer that kept its clear
|
// without this line the only symptom is a framebuffer that kept its clear
|
||||||
// colour. Latched: the early return above only dedupes CONSECUTIVE binds, so an
|
// color. Latched: the early return above only dedupes CONSECUTIVE binds, so an
|
||||||
// app alternating a healthy and a broken program would otherwise log every
|
// app alternating a healthy and a broken program would otherwise log every
|
||||||
// single draw. Parked at MGLOG_I until the level ordering was fixed.
|
// single draw. Parked at MGLOG_I until the level ordering was fixed.
|
||||||
MGLOG_E_ONCE("Backend program for GL program %u is unusable (a shader failed to transpile, "
|
MGLOG_E_ONCE("Backend program for GL program %u is unusable (a shader failed to transpile, "
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_cacheSamplerParameters.borderColorI != samplerParams.borderColorI ||
|
m_cacheSamplerParameters.borderColorI != samplerParams.borderColorI ||
|
||||||
m_cacheSamplerParameters.borderColorUI != samplerParams.borderColorUI ||
|
m_cacheSamplerParameters.borderColorUI != samplerParams.borderColorUI ||
|
||||||
m_cacheSamplerParameters.borderColorForm != samplerParams.borderColorForm) {
|
m_cacheSamplerParameters.borderColorForm != samplerParams.borderColorForm) {
|
||||||
// Same gate as the texture-side border colour above, and the same reason for
|
// Same gate as the texture-side border color above, and the same reason for
|
||||||
// branching on the form: an integer border colour must reach the driver through
|
// branching on the form: an integer border color must reach the driver through
|
||||||
// glSamplerParameterIiv/Iuiv or an integer sampler reads the float's bit pattern
|
// glSamplerParameterIiv/Iuiv or an integer sampler reads the float's bit pattern
|
||||||
// back instead of the value.
|
// back instead of the value.
|
||||||
if (g_GLESCapabilities.SupportsTextureBorderClamp) {
|
if (g_GLESCapabilities.SupportsTextureBorderClamp) {
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A three-channel format widened to four to keep a colour attachment renderable (see
|
// A three-channel format widened to four to keep a color attachment renderable (see
|
||||||
// NormalizePixelFormat) is described to the driver as a four-component transfer, so the
|
// NormalizePixelFormat) is described to the driver as a four-component transfer, so the
|
||||||
// three-component client data has to be repacked with an alpha of 1.0 - otherwise the
|
// three-component client data has to be repacked with an alpha of 1.0 - otherwise the
|
||||||
// driver walks three texels' worth of data per four-texel row and the image shears.
|
// driver walks three texels' worth of data per four-texel row and the image shears.
|
||||||
@@ -467,7 +467,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// The transfer half of the image-format widening: an image-bindable texture whose ES
|
// The transfer half of the image-format widening: an image-bindable texture whose ES
|
||||||
// storage was widened to a core carrier is described to the driver as a four-component
|
// storage was widened to a core carrier is described to the driver as a four-component
|
||||||
// transfer, so its narrower client data has to be repacked the same way the three-channel
|
// transfer, so its narrower client data has to be repacked the same way the three-channel
|
||||||
// colour-renderable widening repacks its own.
|
// color-renderable widening repacks its own.
|
||||||
//
|
//
|
||||||
// Three shapes, because the carriers come in three kinds. Most of them keep the frontend
|
// Three shapes, because the carriers come in three kinds. Most of them keep the frontend
|
||||||
// format's component TYPE and only add channels, so padding the shadow out to four
|
// format's component TYPE and only add channels, so padding the shadow out to four
|
||||||
@@ -836,7 +836,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// consume is a swap-and-pop - so every one of them is taken, used and dropped
|
// consume is a swap-and-pop - so every one of them is taken, used and dropped
|
||||||
// inside one level's iteration, and never held across a consume.
|
// inside one level's iteration, and never held across a consume.
|
||||||
if (pushedStorage != nullptr) {
|
if (pushedStorage != nullptr) {
|
||||||
// THE METADATA RESPECIFY, HONOURED (ID-18 M4, review M-2). BindMask and
|
// THE METADATA RESPECIFY, HONORED (ID-18 M4, review M-2). BindMask and
|
||||||
// ImageBindableHint are STICKY facts the client discovers AFTER allocation - a
|
// ImageBindableHint are STICKY facts the client discovers AFTER allocation - a
|
||||||
// texture first bound as a shader image - and an IMMUTABLE texture never has a
|
// texture first bound as a shader image - and an IMMUTABLE texture never has a
|
||||||
// later redefinition to carry them, so they arrive on a respecify that restates
|
// later redefinition to carry them, so they arrive on a respecify that restates
|
||||||
@@ -868,7 +868,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// ONE compare replaces the whole cheap-gate trio AND the content version. The
|
// ONE compare replaces the whole cheap-gate trio AND the content version. The
|
||||||
// applier bumps Serial on every respecify and every sub-data it applies to this
|
// applier bumps Serial on every respecify and every sub-data it applies to this
|
||||||
// resource, which is exactly the union those four keys covered - without the
|
// resource, which is exactly the union those four keys covered - without the
|
||||||
// coarse behaviour the sampling-resolution generation had, where any texture's
|
// coarse behavior the sampling-resolution generation had, where any texture's
|
||||||
// shape churn re-opened every other texture's gate.
|
// shape churn re-opened every other texture's gate.
|
||||||
//
|
//
|
||||||
// The pending set is the second half and it is not redundant: a previous sync
|
// The pending set is the second half and it is not redundant: a previous sync
|
||||||
@@ -2086,7 +2086,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// transport-gated - safe by a chain rather than by its own statement, which
|
// transport-gated - safe by a chain rather than by its own statement, which
|
||||||
// is exactly the shape that cost the monolith arm 137 scenarios. Under a
|
// is exactly the shape that cost the monolith arm 137 scenarios. Under a
|
||||||
// transport the conjunct is already implied by `pushedStorage != nullptr`, so
|
// transport the conjunct is already implied by `pushedStorage != nullptr`, so
|
||||||
// this changes no behaviour and closes no door; it says the thing instead of
|
// this changes no behavior and closes no door; it says the thing instead of
|
||||||
// depending on it.
|
// depending on it.
|
||||||
const Bool texBufferByRecord = pushedStorage != nullptr && MGB_TEXTURE_HANDLE_ARM_OFF(*this) == false;
|
const Bool texBufferByRecord = pushedStorage != nullptr && MGB_TEXTURE_HANDLE_ARM_OFF(*this) == false;
|
||||||
static const SharedPtr<MG_State::GLState::BufferObject> kNoFrontendBuffer{};
|
static const SharedPtr<MG_State::GLState::BufferObject> kNoFrontendBuffer{};
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// otherwise still claim those values are in force and SyncTextureParamsToBackend
|
// otherwise still claim those values are in force and SyncTextureParamsToBackend
|
||||||
// would skip the whole pass on the unchanged params version, leaving the driver
|
// would skip the whole pass on the unchanged params version, leaving the driver
|
||||||
// texture at defaults for the rest of its life. Latent for swizzle, LOD range and
|
// texture at defaults for the rest of its life. Latent for swizzle, LOD range and
|
||||||
// border colour long before GL_DEPTH_STENCIL_TEXTURE_MODE joined them; the mode
|
// border color long before GL_DEPTH_STENCIL_TEXTURE_MODE joined them; the mode
|
||||||
// makes it visible because falling back to the default silently samples the wrong
|
// makes it visible because falling back to the default silently samples the wrong
|
||||||
// aspect rather than merely mis-filtering.
|
// aspect rather than merely mis-filtering.
|
||||||
m_cacheLodRange = {0, 1000};
|
m_cacheLodRange = {0, 1000};
|
||||||
@@ -835,7 +835,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// NO set_texture_params HAS BEEN APPLIED FOR THIS TEXTURE YET, which is not the same
|
// NO set_texture_params HAS BEEN APPLIED FOR THIS TEXTURE YET, which is not the same
|
||||||
// thing as a malformed one and must not be read as one. ParamsSerial is the
|
// thing as a malformed one and must not be read as one. ParamsSerial is the
|
||||||
// applier's own "have I ever stored a params record here" (it is bumped on every
|
// applier's own "have I ever stored a params record here" (it is bumped on every
|
||||||
// set_texture_params and starts at 0), and Params is value-initialised beside it -
|
// set_texture_params and starts at 0), and Params is value-initialized beside it -
|
||||||
// so on a texture the application has never given a parameter to, BuiltinSampler is
|
// so on a texture the application has never given a parameter to, BuiltinSampler is
|
||||||
// null because the record was never written, not because a client wrote a null.
|
// null because the record was never written, not because a client wrote a null.
|
||||||
// There is nothing to push in that state; SyncTextureParamsToBackend's own gate
|
// There is nothing to push in that state; SyncTextureParamsToBackend's own gate
|
||||||
@@ -912,7 +912,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
// P4a (D-E1): the fifteen sampler values are SAMPLER state (GL 4.6 table 23.18) and
|
// P4a (D-E1): the fifteen sampler values are SAMPLER state (GL 4.6 table 23.18) and
|
||||||
// Espryt pushes them with glTexParameter* onto the TEXTURE rather than with
|
// Espryt pushes them with glTexParameter* onto the TEXTURE rather than with
|
||||||
// glBindSampler onto the unit - behaviour P4a preserves exactly. What changes is
|
// glBindSampler onto the unit - behavior P4a preserves exactly. What changes is
|
||||||
// where the values and the "did they move" answer come from.
|
// where the values and the "did they move" answer come from.
|
||||||
//
|
//
|
||||||
// The whole arm choice is a preprocessor #if/#else rather than a runtime branch
|
// The whole arm choice is a preprocessor #if/#else rather than a runtime branch
|
||||||
@@ -1055,7 +1055,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// independent of any binding - that is what closes D-E3's gap, where a texture that is
|
// independent of any binding - that is what closes D-E3's gap, where a texture that is
|
||||||
// only a READ-framebuffer attachment reaches SyncMipmapsToBackend and nothing else. The
|
// only a READ-framebuffer attachment reaches SyncMipmapsToBackend and nothing else. The
|
||||||
// FORMAT comes from the descriptor beside them, and the BORDER comes from the built-in
|
// FORMAT comes from the descriptor beside them, and the BORDER comes from the built-in
|
||||||
// sampler's CSO (D-F4), because a border colour is sampler state.
|
// sampler's CSO (D-F4), because a border color is sampler state.
|
||||||
#define MGB_TEXPARAM_LEVEL_RANGE \
|
#define MGB_TEXPARAM_LEVEL_RANGE \
|
||||||
(pushedRecord != nullptr ? UintVec2{static_cast<Uint>(pushedRecord->Params.BaseLevel), \
|
(pushedRecord != nullptr ? UintVec2{static_cast<Uint>(pushedRecord->Params.BaseLevel), \
|
||||||
static_cast<Uint>(pushedRecord->Params.MaxLevel)} \
|
static_cast<Uint>(pushedRecord->Params.MaxLevel)} \
|
||||||
@@ -1117,7 +1117,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Bool borderColorReadable = true;
|
Bool borderColorReadable = true;
|
||||||
pushedRecord = ResolvePushedTextureParams(stateTextureObject);
|
pushedRecord = ResolvePushedTextureParams(stateTextureObject);
|
||||||
if (pushedRecord == nullptr) return;
|
if (pushedRecord == nullptr) return;
|
||||||
// D-F4: the border colour is SAMPLER state (GL 4.6 table 23.18) and lives on the
|
// D-F4: the border color is SAMPLER state (GL 4.6 table 23.18) and lives on the
|
||||||
// built-in sampler's CSO, not on MGPTextureParams - P4a deliberately does not
|
// built-in sampler's CSO, not on MGPTextureParams - P4a deliberately does not
|
||||||
// put SamplerParameters on the wire twice. All FOUR comparands (float, int,
|
// put SamplerParameters on the wire twice. All FOUR comparands (float, int,
|
||||||
// uint, form) still cross and are still all compared below, because two integer
|
// uint, form) still cross and are still all compared below, because two integer
|
||||||
@@ -1129,7 +1129,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
} else {
|
} else {
|
||||||
borderColorReadable = false;
|
borderColorReadable = false;
|
||||||
MGLOG_E_ONCE("MGPipe: texture %u's built-in sampler CSO {%u, %u} has no applier "
|
MGLOG_E_ONCE("MGPipe: texture %u's built-in sampler CSO {%u, %u} has no applier "
|
||||||
"record, so its border colour cannot be pushed",
|
"record, so its border color cannot be pushed",
|
||||||
TextureDiagName(stateTextureObject, pushedRecord),
|
TextureDiagName(stateTextureObject, pushedRecord),
|
||||||
pushedRecord->Params.BuiltinSampler.Slot, pushedRecord->Params.BuiltinSampler.Gen);
|
pushedRecord->Params.BuiltinSampler.Slot, pushedRecord->Params.BuiltinSampler.Gen);
|
||||||
}
|
}
|
||||||
@@ -1185,7 +1185,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
MGLOG_D("%s(%s:%d) ES error %s", func, file, line, MG_Util::ConvertGLEnumToString(err).c_str());
|
||||||
});
|
});
|
||||||
|
|
||||||
// A three-channel format widened to four to keep the image colour-renderable (see
|
// A three-channel format widened to four to keep the image color-renderable (see
|
||||||
// NormalizePixelFormat) gains an alpha channel the frontend format does not have, and
|
// NormalizePixelFormat) gains an alpha channel the frontend format does not have, and
|
||||||
// whatever the draw that filled it wrote there is not what GL would report: a format
|
// whatever the draw that filled it wrote there is not what GL would report: a format
|
||||||
// without alpha reads back as 1.0. Answer the ALPHA swizzle source with ONE so the
|
// without alpha reads back as 1.0. Answer the ALPHA swizzle source with ONE so the
|
||||||
@@ -1246,7 +1246,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// GL_TEXTURE_BORDER_COLOR needs ES 3.2 or EXT/OES_texture_border_clamp; on a driver
|
// GL_TEXTURE_BORDER_COLOR needs ES 3.2 or EXT/OES_texture_border_clamp; on a driver
|
||||||
// without it every such call is INVALID_ENUM, so the parameter is simply not synced.
|
// without it every such call is INVALID_ENUM, so the parameter is simply not synced.
|
||||||
//
|
//
|
||||||
// The FORM has to be forwarded along with the value. A border colour set through
|
// The FORM has to be forwarded along with the value. A border color set through
|
||||||
// glTexParameterIiv/Iuiv is an integer one, and an isampler2D/usampler2D fetch of the
|
// glTexParameterIiv/Iuiv is an integer one, and an isampler2D/usampler2D fetch of the
|
||||||
// border returns whatever the driver's integer border register holds - so pushing it
|
// border returns whatever the driver's integer border register holds - so pushing it
|
||||||
// through glTexParameterfv handed the driver float 255.0 and the shader read back
|
// through glTexParameterfv handed the driver float 255.0 and the shader read back
|
||||||
@@ -1259,7 +1259,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// leave the driver holding the first value forever.
|
// leave the driver holding the first value forever.
|
||||||
// m-3: GATED, because on the handle arm an unreadable border means the CSO record is
|
// m-3: GATED, because on the handle arm an unreadable border means the CSO record is
|
||||||
// missing and the block below is skipped with the refusal already named - so v1's
|
// missing and the block below is skipped with the refusal already named - so v1's
|
||||||
// unconditional initialiser was a live frontend read on a switched-over path whose
|
// unconditional initializer was a live frontend read on a switched-over path whose
|
||||||
// value nothing then used. The value a skipped block sees is the cache's own, which
|
// value nothing then used. The value a skipped block sees is the cache's own, which
|
||||||
// cannot make the condition true.
|
// cannot make the condition true.
|
||||||
const auto borderColorForm = borderColorReadable ? MGB_TEXPARAM_BORDER_FORM : m_cacheBorderColorForm;
|
const auto borderColorForm = borderColorReadable ? MGB_TEXPARAM_BORDER_FORM : m_cacheBorderColorForm;
|
||||||
|
|||||||
@@ -597,7 +597,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// already returned. A buffers-only walk leaves the flags as they are (above).
|
// already returned. A buffers-only walk leaves the flags as they are (above).
|
||||||
if (!buffersOnly) HostSetEnabled(attribIndex, attrib.Enabled != 0);
|
if (!buffersOnly) HostSetEnabled(attribIndex, attrib.Enabled != 0);
|
||||||
|
|
||||||
// The fp64 narrowing, verbatim in behaviour including the Adreno workaround:
|
// The fp64 narrowing, verbatim in behavior including the Adreno workaround:
|
||||||
// when no float32 stream can be built the array is DISABLED rather than left
|
// when no float32 stream can be built the array is DISABLED rather than left
|
||||||
// enabled with no pointer, which is what the driver turns into a SIGSEGV inside
|
// enabled with no pointer, which is what the driver turns into a SIGSEGV inside
|
||||||
// the next draw (KHR-GL43.vertex_attrib_binding.basic-input-case4). IsLong is
|
// the next draw (KHR-GL43.vertex_attrib_binding.basic-input-case4). IsLong is
|
||||||
@@ -981,7 +981,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// object - that absence is the design, not a gap in it (ARCHITECTURE.md 4.2). The
|
// object - that absence is the design, not a gap in it (ARCHITECTURE.md 4.2). The
|
||||||
// two ways to keep the site here would each break something D-N or D-J protects: a
|
// two ways to keep the site here would each break something D-N or D-J protects: a
|
||||||
// handle -> object map is the very thing the split removes, and pulling the bytes
|
// handle -> object map is the very thing the split removes, and pulling the bytes
|
||||||
// eagerly on the client at every draw is new behaviour and new cost.
|
// eagerly on the client at every draw is new behavior and new cost.
|
||||||
//
|
//
|
||||||
// SO THE DEVIATION IS DECLARED, WITH ITS BLAST RADIUS. Under the default mask a
|
// SO THE DEVIATION IS DECLARED, WITH ITS BLAST RADIUS. Under the default mask a
|
||||||
// 64-bit vertex array whose SOURCE buffer was written by a shader and not yet pulled
|
// 64-bit vertex array whose SOURCE buffer was written by a shader and not yet pulled
|
||||||
@@ -1104,7 +1104,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// source type and `normalized` (GL accepts BGRA only normalized, and a packed type's
|
// source type and `normalized` (GL accepts BGRA only normalized, and a packed type's
|
||||||
// signedness is the type's own). The narrowed stream is float32, and `normalized` is
|
// signedness is the type's own). The narrowed stream is float32, and `normalized` is
|
||||||
// deliberately GL_FALSE there rather than attrib.Normalized: GL ignores it for
|
// deliberately GL_FALSE there rather than attrib.Normalized: GL ignores it for
|
||||||
// floating-point array types, and honouring it would scale the fetched values.
|
// floating-point array types, and honoring it would scale the fetched values.
|
||||||
const GLint convertedSize = bgra ? 4 : static_cast<GLint>(attrib.Size);
|
const GLint convertedSize = bgra ? 4 : static_cast<GLint>(attrib.Size);
|
||||||
const GLenum convertedType = bgra ? MG_Util::ConvertDataTypeToGLEnum(sourceType) : GL_FLOAT;
|
const GLenum convertedType = bgra ? MG_Util::ConvertDataTypeToGLEnum(sourceType) : GL_FLOAT;
|
||||||
const GLboolean convertedNormalized = (bgra && attrib.Normalized) ? GL_TRUE : GL_FALSE;
|
const GLboolean convertedNormalized = (bgra && attrib.Normalized) ? GL_TRUE : GL_FALSE;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace MobileGL::MG_Backend::DirectGLES::MultiDrawImpl {
|
|||||||
// The flattening dispatch is one invocation per output index. ES 3.1 only
|
// The flattening dispatch is one invocation per output index. ES 3.1 only
|
||||||
// guarantees 65535 work groups per dimension, and exceeding it makes
|
// guarantees 65535 work groups per dimension, and exceeding it makes
|
||||||
// glDispatchCompute an INVALID_VALUE no-op - which would leave the draw reading an
|
// glDispatchCompute an INVALID_VALUE no-op - which would leave the draw reading an
|
||||||
// uninitialised index buffer rather than failing visibly. Cap the tier there
|
// uninitialized index buffer rather than failing visibly. Cap the tier there
|
||||||
// instead of querying: 4.19M indices is far past any real multi-draw batch, and
|
// instead of querying: 4.19M indices is far past any real multi-draw batch, and
|
||||||
// beyond it the per-sub-draw tiers are the better answer anyway.
|
// beyond it the per-sub-draw tiers are the better answer anyway.
|
||||||
constexpr SizeT kComputeWorkGroupSize = 64;
|
constexpr SizeT kComputeWorkGroupSize = 64;
|
||||||
@@ -239,7 +239,7 @@ namespace MobileGL::MG_Backend::DirectGLES::MultiDrawImpl {
|
|||||||
// ---- P5e (ra2), ID-136: THE SEAT THIS FILE'S OWN RULE HAD MISSED -------------------
|
// ---- P5e (ra2), ID-136: THE SEAT THIS FILE'S OWN RULE HAD MISSED -------------------
|
||||||
//
|
//
|
||||||
// This was the LAST unguarded frontend read on the multi-draw apply path, and it sat
|
// This was the LAST unguarded frontend read on the multi-draw apply path, and it sat
|
||||||
// twenty lines above the function that retired its neighbour. It asked
|
// twenty lines above the function that retired its neighbor. It asked
|
||||||
// `gPipeInputs->GetBufferBindingSlot(BufferTarget::DrawIndirect)` and then
|
// `gPipeInputs->GetBufferBindingSlot(BufferTarget::DrawIndirect)` and then
|
||||||
// `EnsureBufferResource(<frontend object>)` - a registry lookup keyed by the client's
|
// `EnsureBufferResource(<frontend object>)` - a registry lookup keyed by the client's
|
||||||
// identity, which is §4.4's rule and not only the allocator's. Under run-ahead that is
|
// identity, which is §4.4's rule and not only the allocator's. Under run-ahead that is
|
||||||
@@ -524,7 +524,7 @@ namespace MobileGL::MG_Backend::DirectGLES::MultiDrawImpl {
|
|||||||
std::memcpy(&value, source + i * 4, sizeof(value));
|
std::memcpy(&value, source + i * 4, sizeof(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Unsigned wraparound is the defined behaviour for a negative base vertex.
|
// Unsigned wraparound is the defined behavior for a negative base vertex.
|
||||||
out[i] = (restartActive && value == restartSentinel) ? 0xFFFFFFFFu : value + baseVertexBits;
|
out[i] = (restartActive && value == restartSentinel) ? 0xFFFFFFFFu : value + baseVertexBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -789,7 +789,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint localIndex = outIndex - (low == 0u ? 0u : drawInfo[(low - 1u) * 3u + 2u]);
|
uint localIndex = outIndex - (low == 0u ? 0u : drawInfo[(low - 1u) * 3u + 2u]);
|
||||||
// Unsigned wraparound is the defined behaviour for a negative base vertex. No
|
// Unsigned wraparound is the defined behavior for a negative base vertex. No
|
||||||
// restart sentinel handling: the tier declines outright while restart is enabled.
|
// restart sentinel handling: the tier declines outright while restart is enabled.
|
||||||
flatIndices[outIndex] = ReadSourceIndex(localIndex + drawInfo[low * 3u]) + drawInfo[low * 3u + 1u];
|
flatIndices[outIndex] = ReadSourceIndex(localIndex + drawInfo[low * 3u]) + drawInfo[low * 3u + 1u];
|
||||||
}
|
}
|
||||||
@@ -1072,7 +1072,7 @@ void main() {
|
|||||||
GLsizei drawcount, const GLint* basevertex) {
|
GLsizei drawcount, const GLint* basevertex) {
|
||||||
if (drawcount <= 0 || !count || !indices) return;
|
if (drawcount <= 0 || !count || !indices) return;
|
||||||
// Read before any GL work, because it decides the tier below: a desktop restart index
|
// Read before any GL work, because it decides the tier below: a desktop restart index
|
||||||
// the driver does not know about can only be honoured by the tier that rewrites the
|
// the driver does not know about can only be honored by the tier that rewrites the
|
||||||
// index stream (see ResolveTierForBatch). A restart index this index type cannot hold
|
// index stream (see ResolveTierForBatch). A restart index this index type cannot hold
|
||||||
// needs no rewrite at all - nothing can match it - but it does need the driver's own
|
// needs no rewrite at all - nothing can match it - but it does need the driver's own
|
||||||
// fixed-index restart held off for the batch, which is what the scope below does.
|
// fixed-index restart held off for the batch, which is what the scope below does.
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
|
|
||||||
String PromoteNarrowIntegerWidthGlobals(String source) {
|
String PromoteNarrowIntegerWidthGlobals(String source) {
|
||||||
for (const char* name : {kNarrowIntegerWidths8GlobalName, kNarrowIntegerWidths16GlobalName}) {
|
for (const char* name : {kNarrowIntegerWidths8GlobalName, kNarrowIntegerWidths16GlobalName}) {
|
||||||
// The zero-initialised Private global is printed with or without a precision qualifier;
|
// The zero-initialized Private global is printed with or without a precision qualifier;
|
||||||
// only a declaration starting its own line is the global itself.
|
// only a declaration starting its own line is the global itself.
|
||||||
for (const char* prefix : {"highp uint ", "mediump uint ", "lowp uint ", "uint "}) {
|
for (const char* prefix : {"highp uint ", "mediump uint ", "lowp uint ", "uint "}) {
|
||||||
Bool promoted = false;
|
Bool promoted = false;
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// THE CALLING THREAD'S BUCKET, not every bucket, and that is the semantic answer
|
// THE CALLING THREAD'S BUCKET, not every bucket, and that is the semantic answer
|
||||||
// rather than a shortcut: a caller walking twins is asking "which of the objects I
|
// rather than a shortcut: a caller walking twins is asking "which of the objects I
|
||||||
// can see need this", and what it can see is its own share group. Every bucket in
|
// can see need this", and what it can see is its own share group. Every bucket in
|
||||||
// one process would walk a neighbour session's objects.
|
// one process would walk a neighbor session's objects.
|
||||||
ForCallingThread().ForEachLive(fn);
|
ForCallingThread().ForEachLive(fn);
|
||||||
}
|
}
|
||||||
// Every bucket, in one pass. The caller receives the key with the handle so it can tell
|
// Every bucket, in one pass. The caller receives the key with the handle so it can tell
|
||||||
@@ -479,7 +479,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// THE TWO DIRECTIONS ARE NOT SYMMETRIC. The handle arrived in a payload, so
|
// THE TWO DIRECTIONS ARE NOT SYMMETRIC. The handle arrived in a payload, so
|
||||||
// `handle.Gen < entry.Gen` is a reachable input, and adopting it would destroy the INCUMBENT LIVE twin - a
|
// `handle.Gen < entry.Gen` is a reachable input, and adopting it would destroy the INCUMBENT LIVE twin - a
|
||||||
// driver buffer id, a persistent map, a pooled store, released by a defaulted destructor that issues no
|
// driver buffer id, a persistent map, a pooled store, released by a defaulted destructor that issues no
|
||||||
// glDeleteBuffers and no pool enrolment - and then stamp the slot back to the dead resource's generation,
|
// glDeleteBuffers and no pool enrollment - and then stamp the slot back to the dead resource's generation,
|
||||||
// after which the incumbent's own FindByHandle refuses it and it is silently handed a fresh, empty twin.
|
// after which the incumbent's own FindByHandle refuses it and it is silently handed a fresh, empty twin.
|
||||||
// That is a leak AND a resource that loses its storage with no diagnostic, i.e. the shape commit d7655247
|
// That is a leak AND a resource that loses its storage with no diagnostic, i.e. the shape commit d7655247
|
||||||
// fixed and the thing MGPipeHandle::Gen exists to prevent. So: forward is a recycle and resets the twin,
|
// fixed and the thing MGPipeHandle::Gen exists to prevent. So: forward is a recycle and resets the twin,
|
||||||
@@ -725,9 +725,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The holder list: intrusive and doubly linked, so registering and unregistering are
|
// The holder list: intrusive and doubly linked, so registering and unregistering are
|
||||||
// two pointer writes with no allocation, and its head is a constant-initialised
|
// two pointer writes with no allocation, and its head is a constant-initialized
|
||||||
// static - which is what lets the process-lifetime registry globals in Managers.cpp
|
// static - which is what lets the process-lifetime registry globals in Managers.cpp
|
||||||
// link themselves in from their own constructors with no initialisation-order
|
// link themselves in from their own constructors with no initialization-order
|
||||||
// question to answer. Single-threaded, like every table it links (the tables live and
|
// question to answer. Single-threaded, like every table it links (the tables live and
|
||||||
// die on the context thread, as the notice they answer does).
|
// die on the context thread, as the notice they answer does).
|
||||||
void LinkHolder() {
|
void LinkHolder() {
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace TextureImpl {
|
namespace TextureImpl {
|
||||||
// Every image that can back a colour attachment needs a colour-renderable storage format,
|
// Every image that can back a color attachment needs a color-renderable storage format,
|
||||||
// and ES has no renderable three-channel format at all: a three-channel float fallback is
|
// and ES has no renderable three-channel format at all: a three-channel float fallback is
|
||||||
// a legal ES texture but neither legal multisample storage nor a legal attachment, so
|
// a legal ES texture but neither legal multisample storage nor a legal attachment, so
|
||||||
// GL_RGB8_SNORM / GL_RGB16F / ... have to be widened to four channels for any of them.
|
// GL_RGB8_SNORM / GL_RGB16F / ... have to be widened to four channels for any of them.
|
||||||
@@ -178,7 +178,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// allocating it byte for byte.
|
// allocating it byte for byte.
|
||||||
//
|
//
|
||||||
// Do NOT read that as "nothing changes off-device". Measured on llvmpipe 26.1.6
|
// Do NOT read that as "nothing changes off-device". Measured on llvmpipe 26.1.6
|
||||||
// (the headless CI driver), an ES 3.2 GL_TEXTURE_2D colour attachment is COMPLETE for
|
// (the headless CI driver), an ES 3.2 GL_TEXTURE_2D color attachment is COMPLETE for
|
||||||
// GL_RGB8 and GL_RGB16F but INCOMPLETE_ATTACHMENT for GL_RGB8_SNORM, GL_SRGB8 and every
|
// GL_RGB8 and GL_RGB16F but INCOMPLETE_ATTACHMENT for GL_RGB8_SNORM, GL_SRGB8 and every
|
||||||
// RGB integer format, and UNSUPPORTED for GL_RGB32F. Those eight formats therefore DO
|
// RGB integer format, and UNSUPPORTED for GL_RGB32F. Those eight formats therefore DO
|
||||||
// take the widened path on llvmpipe, which is where the retrace fixtures and the glcts
|
// take the widened path on llvmpipe, which is where the retrace fixtures and the glcts
|
||||||
@@ -798,7 +798,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// geometry STAGES core but leaves gl_PointSize out of their gl_PerVertex entirely,
|
// geometry STAGES core but leaves gl_PointSize out of their gl_PerVertex entirely,
|
||||||
// and SPIRV-Cross - which only ever sees a SPIR-V BuiltIn PointSize decoration -
|
// and SPIRV-Cross - which only ever sees a SPIR-V BuiltIn PointSize decoration -
|
||||||
// prints the identifier with no directive behind it. Same hard rule as the two
|
// prints the identifier with no directive behind it. Same hard rule as the two
|
||||||
// neighbours: never emitted speculatively, because `#extension` on a name the driver
|
// neighbors: never emitted speculatively, because `#extension` on a name the driver
|
||||||
// does not advertise is a compile error of its own.
|
// does not advertise is a compile error of its own.
|
||||||
if (extensionName == nullptr || glslCode.find(extensionName) != String::npos) {
|
if (extensionName == nullptr || glslCode.find(extensionName) != String::npos) {
|
||||||
return glslCode;
|
return glslCode;
|
||||||
@@ -831,7 +831,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
static const std::regex imageDeclRegex(
|
static const std::regex imageDeclRegex(
|
||||||
R"((layout\s*\(([^)]*)\)\s*)?uniform\s+(?:(?:readonly|writeonly|coherent|volatile|restrict|highp|mediump|lowp)\s+)*[iu]?image[A-Za-z0-9]+\s+([A-Za-z_][A-Za-z0-9_]*)\s*(\[[^\]]*\])?\s*;)");
|
R"((layout\s*\(([^)]*)\)\s*)?uniform\s+(?:(?:readonly|writeonly|coherent|volatile|restrict|highp|mediump|lowp)\s+)*[iu]?image[A-Za-z0-9]+\s+([A-Za-z_][A-Za-z0-9_]*)\s*(\[[^\]]*\])?\s*;)");
|
||||||
// Every image format spelling GLSL has, so a declaration that already carries one is
|
// Every image format spelling GLSL has, so a declaration that already carries one is
|
||||||
// recognised whatever it says - the caller's map is consulted only for declarations
|
// recognized whatever it says - the caller's map is consulted only for declarations
|
||||||
// with NO format, never to override a written one.
|
// with NO format, never to override a written one.
|
||||||
static const std::regex existingFormatRegex(
|
static const std::regex existingFormatRegex(
|
||||||
R"(\b(rgba32f|rgba16f|rg32f|rg16f|r11f_g11f_b10f|r32f|r16f|rgba16|rgb10_a2|rg16|rg8|r16|r8|rgba16_snorm|rgba8_snorm|rg16_snorm|rg8_snorm|r16_snorm|r8_snorm|rgba32i|rgba16i|rgba8i|rg32i|rg16i|rg8i|r32i|r16i|r8i|rgba32ui|rgba16ui|rgba8ui|rgb10_a2ui|rg32ui|rg16ui|rg8ui|r32ui|r16ui|r8ui)\b)");
|
R"(\b(rgba32f|rgba16f|rg32f|rg16f|r11f_g11f_b10f|r32f|r16f|rgba16|rgb10_a2|rg16|rg8|r16|r8|rgba16_snorm|rgba8_snorm|rg16_snorm|rg8_snorm|r16_snorm|r8_snorm|rgba32i|rgba16i|rgba8i|rg32i|rg16i|rg8i|r32i|r16i|r8i|rgba32ui|rgba16ui|rgba8ui|rgb10_a2ui|rg32ui|rg16ui|rg8ui|r32ui|r16ui|r8ui)\b)");
|
||||||
@@ -1124,7 +1124,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
source += "precision highp float;\n";
|
source += "precision highp float;\n";
|
||||||
source += "precision highp int;\n";
|
source += "precision highp int;\n";
|
||||||
source += "layout(vertices = " + std::to_string(patchVertices) + ") out;\n";
|
source += "layout(vertices = " + std::to_string(patchVertices) + ") out;\n";
|
||||||
// Mirrored, never invented. An empty member list means the neighbouring stage did not
|
// Mirrored, never invented. An empty member list means the neighboring stage did not
|
||||||
// redeclare the block either, and the driver's own built-in declaration is then what
|
// redeclare the block either, and the driver's own built-in declaration is then what
|
||||||
// both sides agree on - redeclaring here would be the thing that broke the match.
|
// both sides agree on - redeclaring here would be the thing that broke the match.
|
||||||
if (!inPerVertexMembers.empty()) {
|
if (!inPerVertexMembers.empty()) {
|
||||||
@@ -1783,7 +1783,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// Nothing downstream reads these names: the two passes that key on the GL uniform
|
// Nothing downstream reads these names: the two passes that key on the GL uniform
|
||||||
// name (RebindImageUniformsToFrontendUnits, BakeImageFormatQualifiers) both run
|
// name (RebindImageUniformsToFrontendUnits, BakeImageFormatQualifiers) both run
|
||||||
// BEFORE this one, RemoveLayoutBinding recognises an image declaration by its TYPE
|
// BEFORE this one, RemoveLayoutBinding recognizes an image declaration by its TYPE
|
||||||
// token, and CacheResourceLocations skips image uniforms outright because ES image
|
// token, and CacheResourceLocations skips image uniforms outright because ES image
|
||||||
// units come only from layout(binding=N). The declarations this pass LEAVES ALONE -
|
// units come only from layout(binding=N). The declarations this pass LEAVES ALONE -
|
||||||
// already readonly/writeonly in the source, or r32f/r32i/r32ui, which need no
|
// already readonly/writeonly in the source, or r32f/r32i/r32ui, which need no
|
||||||
@@ -1825,7 +1825,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Both halves carry `coherent`; see BuildImageDeclaration. The
|
// Both halves carry `coherent`; see BuildImageDeclaration. The
|
||||||
// single-declaration cases below stay as they were - nothing aliases them, so
|
// single-declaration cases below stay as they were - nothing aliases them, so
|
||||||
// there is no visibility to restore and no reason to pay for the cache
|
// there is no visibility to restore and no reason to pay for the cache
|
||||||
// behaviour.
|
// behavior.
|
||||||
edits.push_back({decl.declStart, decl.declLength,
|
edits.push_back({decl.declStart, decl.declLength,
|
||||||
BuildImageDeclaration(decl, "readonly", decl.aliasName,
|
BuildImageDeclaration(decl, "readonly", decl.aliasName,
|
||||||
/*forceCoherent=*/true) +
|
/*forceCoherent=*/true) +
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
} // namespace VertexArrayImpl
|
} // namespace VertexArrayImpl
|
||||||
|
|
||||||
namespace TextureImpl {
|
namespace TextureImpl {
|
||||||
// Whether images on this format-capability target can back a colour attachment, and so
|
// Whether images on this format-capability target can back a color attachment, and so
|
||||||
// need a colour-renderable storage format even when the frontend asked for a
|
// need a color-renderable storage format even when the frontend asked for a
|
||||||
// three-channel one ES never renders to. Shared by the capability probe (which passes the
|
// three-channel one ES never renders to. Shared by the capability probe (which passes the
|
||||||
// capabilities it has just queried, before the globals are published) and by the
|
// capabilities it has just queried, before the globals are published) and by the
|
||||||
// allocation path (which reads the active backend's), so the format the cache was probed
|
// allocation path (which reads the active backend's), so the format the cache was probed
|
||||||
@@ -74,7 +74,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
Bool ShouldUseCaveatTextureFormat(TextureInternalFormat internalFormat, TextureTarget target);
|
Bool ShouldUseCaveatTextureFormat(TextureInternalFormat internalFormat, TextureTarget target);
|
||||||
|
|
||||||
// True when the format the image is actually created with has an alpha channel the
|
// True when the format the image is actually created with has an alpha channel the
|
||||||
// frontend format does not (the three-channel colour-renderable widening). GL reads such
|
// frontend format does not (the three-channel color-renderable widening). GL reads such
|
||||||
// a channel back as 1.0, so any swizzle source of ALPHA has to be answered with ONE and
|
// a channel back as 1.0, so any swizzle source of ALPHA has to be answered with ONE and
|
||||||
// any readback of the image has to overwrite the alpha the draw happened to leave there.
|
// any readback of the image has to overwrite the alpha the draw happened to leave there.
|
||||||
Bool BackendTextureFormatAddsAlpha(TextureInternalFormat internalFormat, TextureTarget target);
|
Bool BackendTextureFormatAddsAlpha(TextureInternalFormat internalFormat, TextureTarget target);
|
||||||
@@ -105,7 +105,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
//
|
//
|
||||||
// The widened triple REPLACES what GenerateTextureFormatInfo chose, including any
|
// The widened triple REPLACES what GenerateTextureFormatInfo chose, including any
|
||||||
// renderability substitution: an image that cannot be image-bound is useless whatever its
|
// renderability substitution: an image that cannot be image-bound is useless whatever its
|
||||||
// attachment behaviour, so the image constraint wins. In practice that only bites
|
// attachment behavior, so the image constraint wins. In practice that only bites
|
||||||
// RG8_SNORM/R8_SNORM on a driver without EXT_render_snorm, where the storage stays
|
// RG8_SNORM/R8_SNORM on a driver without EXT_render_snorm, where the storage stays
|
||||||
// signed-normalized instead of becoming the half float that fallback would have picked -
|
// signed-normalized instead of becoming the half float that fallback would have picked -
|
||||||
// so an image-bound texture in one of those two formats is no longer attachable, and
|
// so an image-bound texture in one of those two formats is no longer attachable, and
|
||||||
@@ -115,11 +115,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// compiled at all, so nothing that works today is being given up.
|
// compiled at all, so nothing that works today is being given up.
|
||||||
//
|
//
|
||||||
// KNOWN GAP, for the same "all three layers move together" reason: a widened texture that
|
// KNOWN GAP, for the same "all three layers move together" reason: a widened texture that
|
||||||
// is ALSO an FBO colour attachment gains one to three writable channels, and a draw into
|
// is ALSO an FBO color attachment gains one to three writable channels, and a draw into
|
||||||
// it can leave values in channels GL says are 0 and 1. Sampling and imageLoad are covered
|
// it can leave values in channels GL says are 0 and 1. Sampling and imageLoad are covered
|
||||||
// (the swizzle composition in SyncTextureParamsToBackend and the shader-side mask), but a
|
// (the swizzle composition in SyncTextureParamsToBackend and the shader-side mask), but a
|
||||||
// glReadPixels/glGetTexImage that asks for more channels than the frontend format has
|
// glReadPixels/glGetTexImage that asks for more channels than the frontend format has
|
||||||
// would see them. Closing it needs the per-draw-buffer colour mask the three-channel
|
// would see them. Closing it needs the per-draw-buffer color mask the three-channel
|
||||||
// widening already carries (FramebufferImpl::g_alphaWidenedDrawBufferMask) generalized
|
// widening already carries (FramebufferImpl::g_alphaWidenedDrawBufferMask) generalized
|
||||||
// from "alpha" to a channel count, which is its own change.
|
// from "alpha" to a channel count, which is its own change.
|
||||||
// How the FRONTEND's CPU shadow for a widened format is laid out relative to the carrier's
|
// How the FRONTEND's CPU shadow for a widened format is laid out relative to the carrier's
|
||||||
@@ -319,7 +319,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// Exists so BuildPassthroughTessControlEssl can MIRROR the stages it has to sit between
|
// Exists so BuildPassthroughTessControlEssl can MIRROR the stages it has to sit between
|
||||||
// rather than guess at them. Whether SPIRV-Cross redeclares the built-in block, and with
|
// rather than guess at them. Whether SPIRV-Cross redeclares the built-in block, and with
|
||||||
// which members, depends on what the application's shader touched; a synthesized stage
|
// which members, depends on what the application's shader touched; a synthesized stage
|
||||||
// that redeclares a different shape than its neighbours is an ES link error against a
|
// that redeclares a different shape than its neighbors is an ES link error against a
|
||||||
// program that has no other problem.
|
// program that has no other problem.
|
||||||
std::optional<String> ExtractPerVertexBlockMembers(const String& essl, Bool input);
|
std::optional<String> ExtractPerVertexBlockMembers(const String& essl, Bool input);
|
||||||
// Moves the clip/cull distance OUTPUTS of a vertex, tessellation evaluation or geometry
|
// Moves the clip/cull distance OUTPUTS of a vertex, tessellation evaluation or geometry
|
||||||
@@ -365,15 +365,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// bound in its place, and every draw silently renders nothing.
|
// bound in its place, and every draw silently renders nothing.
|
||||||
//
|
//
|
||||||
// `inPerVertexMembers` / `outPerVertexMembers` are the member lists to redeclare gl_in
|
// `inPerVertexMembers` / `outPerVertexMembers` are the member lists to redeclare gl_in
|
||||||
// and gl_out with - normally taken from the neighbouring stages' own emitted ESSL via
|
// and gl_out with - normally taken from the neighboring stages' own emitted ESSL via
|
||||||
// ExtractPerVertexBlockMembers, and empty to leave the driver's built-in declaration
|
// ExtractPerVertexBlockMembers, and empty to leave the driver's built-in declaration
|
||||||
// alone, which is what matching a neighbour that did not redeclare requires.
|
// alone, which is what matching a neighbor that did not redeclare requires.
|
||||||
//
|
//
|
||||||
// All four outer levels and both inner levels are written unconditionally: writing a
|
// All four outer levels and both inner levels are written unconditionally: writing a
|
||||||
// level the evaluation stage's domain does not use is legal and ignored, and it saves
|
// level the evaluation stage's domain does not use is legal and ignored, and it saves
|
||||||
// this from having to know the domain. They are the GL_PATCH_DEFAULT_OUTER_LEVEL /
|
// this from having to know the domain. They are the GL_PATCH_DEFAULT_OUTER_LEVEL /
|
||||||
// GL_PATCH_DEFAULT_INNER_LEVEL state, baked in as literals - ES has no such state and no
|
// GL_PATCH_DEFAULT_INNER_LEVEL state, baked in as literals - ES has no such state and no
|
||||||
// glPatchParameterfv to forward to, so compiling them in is the only way to honour them.
|
// glPatchParameterfv to forward to, so compiling them in is the only way to honor them.
|
||||||
// That makes them part of what a built program is stale against, exactly as PATCH_VERTICES
|
// That makes them part of what a built program is stale against, exactly as PATCH_VERTICES
|
||||||
// is: see the staleness clause in DirectGLES.cpp's SyncCurrentProgram, which compares both.
|
// is: see the staleness clause in DirectGLES.cpp's SyncCurrentProgram, which compares both.
|
||||||
//
|
//
|
||||||
@@ -524,7 +524,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
// suffix is the sampler's own name.
|
// suffix is the sampler's own name.
|
||||||
constexpr const char* MS_SAMPLE_MAX_UNIFORM_PREFIX = "mg_msSampleMax_";
|
constexpr const char* MS_SAMPLE_MAX_UNIFORM_PREFIX = "mg_msSampleMax_";
|
||||||
// The runtime half of ClampMultisampleFetchPass's deferDirectUnsignedFetches. A
|
// The runtime half of ClampMultisampleFetchPass's deferDirectUnsignedFetches. A
|
||||||
// usampler2DMS[Array] reads integer colour textures, which the backend may allocate with
|
// usampler2DMS[Array] reads integer color textures, which the backend may allocate with
|
||||||
// fewer samples than MobileGL advertises, AND the stencil aspect of multisample
|
// fewer samples than MobileGL advertises, AND the stencil aspect of multisample
|
||||||
// depth/stencil textures, which it allocates under the (larger) depth ceiling - so no
|
// depth/stencil textures, which it allocates under the (larger) depth ceiling - so no
|
||||||
// single compile-time bound is right for both. Declares one
|
// single compile-time bound is right for both. Declares one
|
||||||
|
|||||||
@@ -878,7 +878,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
E_GL_ARB_texture_rg,
|
E_GL_ARB_texture_rg,
|
||||||
// GL_DEPTH_COMPONENT32F and GL_DEPTH32F_STENCIL8.
|
// GL_DEPTH_COMPONENT32F and GL_DEPTH32F_STENCIL8.
|
||||||
E_GL_ARB_depth_buffer_float,
|
E_GL_ARB_depth_buffer_float,
|
||||||
// The floating-point colour formats. Unlike the rest of this block this string DOES
|
// The floating-point color formats. Unlike the rest of this block this string DOES
|
||||||
// gate CTS cases - KHR-GL4*.internalformat.texture2d.*{16f,32f} is keyed on it with no
|
// gate CTS cases - KHR-GL4*.internalformat.texture2d.*{16f,32f} is keyed on it with no
|
||||||
// core-version fallback, so eight cases per version list were NotSupported on formats
|
// core-version fallback, so eight cases per version list were NotSupported on formats
|
||||||
// the backend has always had.
|
// the backend has always had.
|
||||||
@@ -895,7 +895,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// - multiple capture buffers per stream, gl_SkipComponents / gl_NextBuffer, the
|
// - multiple capture buffers per stream, gl_SkipComponents / gl_NextBuffer, the
|
||||||
// indexed queries and glDrawTransformFeedbackStream (4.0);
|
// indexed queries and glDrawTransformFeedbackStream (4.0);
|
||||||
E_GL_ARB_transform_feedback3,
|
E_GL_ARB_transform_feedback3,
|
||||||
// - GL_RGB10_A2UI (3.3), GL_RGB9_E5 (3.0) and the integer colour formats (3.0);
|
// - GL_RGB10_A2UI (3.3), GL_RGB9_E5 (3.0) and the integer color formats (3.0);
|
||||||
E_GL_ARB_texture_rgb10_a2ui, E_GL_EXT_texture_shared_exponent, E_GL_EXT_texture_integer,
|
E_GL_ARB_texture_rgb10_a2ui, E_GL_EXT_texture_shared_exponent, E_GL_EXT_texture_integer,
|
||||||
// - the eleven pipeline-statistics query targets (4.6). Accepted by glBeginQuery and
|
// - the eleven pipeline-statistics query targets (4.6). Accepted by glBeginQuery and
|
||||||
// answered with GL_QUERY_COUNTER_BITS = 0, the spec's own "this counter is not
|
// answered with GL_QUERY_COUNTER_BITS = 0, the spec's own "this counter is not
|
||||||
@@ -941,7 +941,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// recorded trace can never cover: Iris and Sodium change their SUBMISSION SCHEDULE
|
// recorded trace can never cover: Iris and Sodium change their SUBMISSION SCHEDULE
|
||||||
// the moment they see it - they enqueue whole pipeline batches and poll
|
// the moment they see it - they enqueue whole pipeline batches and poll
|
||||||
// GL_COMPLETION_STATUS_KHR instead of compiling one program at a time - so
|
// GL_COMPLETION_STATUS_KHR instead of compiling one program at a time - so
|
||||||
// MOBILEGL_ASYNC_SHADER_COMPILE=0 has to withdraw the application-visible behaviour
|
// MOBILEGL_ASYNC_SHADER_COMPILE=0 has to withdraw the application-visible behavior
|
||||||
// change as well as the threading, or the kill switch would only be half a switch.
|
// change as well as the threading, or the kill switch would only be half a switch.
|
||||||
if (MG_Util::Async::AsyncShaderCompileEnabled()) {
|
if (MG_Util::Async::AsyncShaderCompileEnabled()) {
|
||||||
extensions.push_back(E_GL_KHR_parallel_shader_compile);
|
extensions.push_back(E_GL_KHR_parallel_shader_compile);
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// GetProgramResourceCache does it - over a multi-stage program with an arrayed SSBO and an
|
// GetProgramResourceCache does it - over a multi-stage program with an arrayed SSBO and an
|
||||||
// atomic-counter block, and asserts element-for-element equality with what the archive
|
// atomic-counter block, and asserts element-for-element equality with what the archive
|
||||||
// published. That equivalence is what makes an #if here a build-time SELECTION rather than
|
// published. That equivalence is what makes an #if here a build-time SELECTION rather than
|
||||||
// a behavioural fork, and it is the reason the case exists.
|
// a behavioral fork, and it is the reason the case exists.
|
||||||
//
|
//
|
||||||
// WHY AN #if AT ALL, AND WHAT IT COSTS. LinkArtifacts::storageBlocks is
|
// WHY AN #if AT ALL, AND WHAT IT COSTS. LinkArtifacts::storageBlocks is
|
||||||
// MOBILEGL_BUILD_DISAGGREGATED-only, because one more Vector member changes the struct's
|
// MOBILEGL_BUILD_DISAGGREGATED-only, because one more Vector member changes the struct's
|
||||||
@@ -263,7 +263,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
};
|
};
|
||||||
auto it = find(name);
|
auto it = find(name);
|
||||||
if (it == blocks.end()) {
|
if (it == blocks.end()) {
|
||||||
// Archive names are normalised, so an arrayed block that GL enumerates per element
|
// Archive names are normalized, so an arrayed block that GL enumerates per element
|
||||||
// - "B[0]", "B[1]" - is one entry here, spelled "B". Same second chance the cache
|
// - "B[0]", "B[1]" - is one entry here, spelled "B". Same second chance the cache
|
||||||
// gave, for the same callers.
|
// gave, for the same callers.
|
||||||
const auto bracket = name.rfind('[');
|
const auto bracket = name.rfind('[');
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
//
|
//
|
||||||
// SessionLocal<T> is that copy. It resolves through the CALLING THREAD's bound MagmaSession, and to
|
// SessionLocal<T> is that copy. It resolves through the CALLING THREAD's bound MagmaSession, and to
|
||||||
// the process-wide default session on every thread nothing bound - which is the monolith, the client
|
// the process-wide default session on every thread nothing bound - which is the monolith, the client
|
||||||
// role and every unit case, i.e. exactly the old behaviour, on whatever thread the app renders from.
|
// role and every unit case, i.e. exactly the old behavior, on whatever thread the app renders from.
|
||||||
// A served session's backend owns its MagmaSession and binds it on its apply thread (the only thread
|
// A served session's backend owns its MagmaSession and binds it on its apply thread (the only thread
|
||||||
// that runs that session's backend), so the two never mix.
|
// that runs that session's backend), so the two never mix.
|
||||||
|
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The barrier belongs in the frame's own recording. Bailing out because
|
// The barrier belongs in the frame's own recording. Bailing out because
|
||||||
// something was already recorded (the previous behaviour) dropped the
|
// something was already recorded (the previous behavior) dropped the
|
||||||
// transition entirely for every frame that never ran a default-framebuffer
|
// transition entirely for every frame that never ran a default-framebuffer
|
||||||
// render pass - the only other thing that carries the image to
|
// render pass - the only other thing that carries the image to
|
||||||
// PRESENT_SRC_KHR, via that pass's finalLayout - so the swapchain image was
|
// PRESENT_SRC_KHR, via that pass's finalLayout - so the swapchain image was
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// wire draw path entirely - this header no longer includes spirv_reflect.h at all.
|
// wire draw path entirely - this header no longer includes spirv_reflect.h at all.
|
||||||
Uint GetShaderStorageBlockIndex(const String& name) const {
|
Uint GetShaderStorageBlockIndex(const String& name) const {
|
||||||
const auto& blocks = Link().storageBlocks;
|
const auto& blocks = Link().storageBlocks;
|
||||||
// The archive carries NORMALISED names (the array subscript stripped), because
|
// The archive carries NORMALIZED names (the array subscript stripped), because
|
||||||
// that is the spelling SPIRV-Reflect's type_name gives and the spelling
|
// that is the spelling SPIRV-Reflect's type_name gives and the spelling
|
||||||
// ProgramFactory::ReflectLayout looks up. A caller that still holds a GL-style
|
// ProgramFactory::ReflectLayout looks up. A caller that still holds a GL-style
|
||||||
// "Foo[2]" gets the same second chance it always had.
|
// "Foo[2]" gets the same second chance it always had.
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// call was DEBUG-or-env gated and only logged, so an invalid module produced by a backend
|
// call was DEBUG-or-env gated and only logged, so an invalid module produced by a backend
|
||||||
// transform went straight to vkCreateShaderModule. That is not a survivable outcome on
|
// transform went straight to vkCreateShaderModule. That is not a survivable outcome on
|
||||||
// this hardware - Mali r54 SIGSEGVs building the pipeline instead of returning an error,
|
// this hardware - Mali r54 SIGSEGVs building the pipeline instead of returning an error,
|
||||||
// the same "not a validating entry point" behaviour PipelineFactory already documents for
|
// the same "not a validating entry point" behavior PipelineFactory already documents for
|
||||||
// vkCreateGraphicsPipelines - so the callers that feed the driver now act on it.
|
// vkCreateGraphicsPipelines - so the callers that feed the driver now act on it.
|
||||||
//
|
//
|
||||||
// This function does NOT log the failure at E any more. It used to, unlatched, on the
|
// This function does NOT log the failure at E any more. It used to, unlatched, on the
|
||||||
@@ -972,7 +972,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
//
|
//
|
||||||
// Deliberately conservative - it answers "assume yes" for every shape it cannot read
|
// Deliberately conservative - it answers "assume yes" for every shape it cannot read
|
||||||
// exactly, because a false "no" would silently drop the clip-space fixup from a shader
|
// exactly, because a false "no" would silently drop the clip-space fixup from a shader
|
||||||
// that does write gl_Position, while a false "yes" only reinstates the behaviour this
|
// that does write gl_Position, while a false "yes" only reinstates the behavior this
|
||||||
// pass has always had. Scans every function rather than just the entry point's: a shader
|
// pass has always had. Scans every function rather than just the entry point's: a shader
|
||||||
// that assigns gl_Position inside a helper is still a shader that writes it, and passing
|
// that assigns gl_Position inside a helper is still a shader that writes it, and passing
|
||||||
// the pointer to a call is a write as far as this can tell.
|
// the pointer to a call is a write as far as this can tell.
|
||||||
@@ -1089,7 +1089,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (!FindPositionTarget(context(), &target)) return Status::SuccessWithoutChange;
|
if (!FindPositionTarget(context(), &target)) return Status::SuccessWithoutChange;
|
||||||
|
|
||||||
// Nothing to remap in a Position the shader never writes. Declining is not just
|
// Nothing to remap in a Position the shader never writes. Declining is not just
|
||||||
// an optimisation: the fixup is load-modify-store, so on an unwritten Position it
|
// an optimization: the fixup is load-modify-store, so on an unwritten Position it
|
||||||
// converts "undefined, never written" into "written with whatever the load
|
// converts "undefined, never written" into "written with whatever the load
|
||||||
// returned", and the store is a reference to a variable the link-time sanitize
|
// returned", and the store is a reference to a variable the link-time sanitize
|
||||||
// chain has already delisted from the entry-point interface. glslang emits the
|
// chain has already delisted from the entry-point interface. glslang emits the
|
||||||
@@ -1165,7 +1165,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// ivec2(gl_FragCoord.xy)) into an image exactly the size of that viewport, so every
|
// ivec2(gl_FragCoord.xy)) into an image exactly the size of that viewport, so every
|
||||||
// store fell outside the image and the test read back zeroes.
|
// store fell outside the image and the test read back zeroes.
|
||||||
//
|
//
|
||||||
// The rewrite redirects every read of the builtin to a Private copy initialised once at
|
// The rewrite redirects every read of the builtin to a Private copy initialized once at
|
||||||
// entry, which is exact for all access forms (whole-vector loads, `.y` access chains,
|
// entry, which is exact for all access forms (whole-vector loads, `.y` access chains,
|
||||||
// OpCopyMemory) and leaves the builtin itself - and its decorations - untouched.
|
// OpCopyMemory) and leaves the builtin itself - and its decorations - untouched.
|
||||||
class GlFragCoordYFlipPass final : public spvtools::opt::Pass {
|
class GlFragCoordYFlipPass final : public spvtools::opt::Pass {
|
||||||
@@ -1233,7 +1233,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
{SPV_OPERAND_TYPE_STORAGE_CLASS, {static_cast<Uint32>(spv::StorageClass::Private)}}});
|
{SPV_OPERAND_TYPE_STORAGE_CLASS, {static_cast<Uint32>(spv::StorageClass::Private)}}});
|
||||||
context()->AddGlobalValue(std::move(copyVar));
|
context()->AddGlobalValue(std::move(copyVar));
|
||||||
|
|
||||||
// Redirect the reads BEFORE emitting the initialiser, so the initialiser's own
|
// Redirect the reads BEFORE emitting the initializer, so the initializer's own
|
||||||
// load of the builtin is not rewritten into a load of the (still empty) copy.
|
// load of the builtin is not rewritten into a load of the (still empty) copy.
|
||||||
if (!RedirectReads(builtinVarId, copyVarId)) return Status::SuccessWithoutChange;
|
if (!RedirectReads(builtinVarId, copyVarId)) return Status::SuccessWithoutChange;
|
||||||
|
|
||||||
@@ -1688,7 +1688,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Adreno 650 (driver 512.502) faults the GPU on an implicit-LOD sample of a full-screen
|
// Adreno 650 (driver 512.502) faults the GPU on an implicit-LOD sample of a full-screen
|
||||||
// colour render target: the texture unit's derivative path reads outside the image's
|
// color render target: the texture unit's derivative path reads outside the image's
|
||||||
// allocation even though the sampler clamps LOD to 0 and the mapping is 1:1. MobileGL's
|
// allocation even though the sampler clamps LOD to 0 and the mapping is 1:1. MobileGL's
|
||||||
// own default-framebuffer blit shader works around it with textureLod, but an
|
// own default-framebuffer blit shader works around it with textureLod, but an
|
||||||
// application's shader (Minecraft's blit.fsh is `texture(InSampler, texCoord)`) cannot be
|
// application's shader (Minecraft's blit.fsh is `texture(InSampler, texCoord)`) cannot be
|
||||||
@@ -2146,7 +2146,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// GetOrCreateProgram's MOBILEGL_ASSERT(remapOk) as the only complaint, and
|
// GetOrCreateProgram's MOBILEGL_ASSERT(remapOk) as the only complaint, and
|
||||||
// that assert compiles out above DEBUG - so a release build SILENTLY kept
|
// that assert compiles out above DEBUG - so a release build SILENTLY kept
|
||||||
// glslang's per-stage auto-mapped binding numbers, skipping the cross-stage
|
// glslang's per-stage auto-mapped binding numbers, skipping the cross-stage
|
||||||
// unification and the set->0 normalisation this function exists to do. A
|
// unification and the set->0 normalization this function exists to do. A
|
||||||
// program with an image array plus any second descriptor got aliased
|
// program with an image array plus any second descriptor got aliased
|
||||||
// bindings out of that, and a DEBUG build trapped on the same program.
|
// bindings out of that, and a DEBUG build trapped on the same program.
|
||||||
// The refusal below is MGLOG_E and per-program-compile, so it reports every
|
// The refusal below is MGLOG_E and per-program-compile, so it reports every
|
||||||
@@ -2989,7 +2989,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
MGLOG_D("ProgramFactory::ReflectLayout: %s array '%s' at binding %u spans %u descriptors but the "
|
MGLOG_D("ProgramFactory::ReflectLayout: %s array '%s' at binding %u spans %u descriptors but the "
|
||||||
"reflection reserved fewer uniform locations for it (base=%d) - a multi-dimensional array "
|
"reflection reserved fewer uniform locations for it (base=%d) - a multi-dimensional array "
|
||||||
"is the usual cause, and MobileGL declines it rather than resolve elements onto a "
|
"is the usual cause, and MobileGL declines it rather than resolve elements onto a "
|
||||||
"neighbouring uniform",
|
"neighboring uniform",
|
||||||
kindLabel, uniformName.c_str(), binding, count, baseLocation);
|
kindLabel, uniformName.c_str(), binding, count, baseLocation);
|
||||||
outDeclined = true;
|
outDeclined = true;
|
||||||
}
|
}
|
||||||
@@ -3530,7 +3530,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
"ProgramFactory::ReflectLayout, vkCreatePipelineLayout");
|
"ProgramFactory::ReflectLayout, vkCreatePipelineLayout");
|
||||||
|
|
||||||
// Built here rather than where bindingKinds is sized: at that point the vector is only
|
// Built here rather than where bindingKinds is sized: at that point the vector is only
|
||||||
// zero-initialised and the kinds are assigned further down, so a list built there would be
|
// zero-initialized and the kinds are assigned further down, so a list built there would be
|
||||||
// empty. Ascending by construction because the index walks upward.
|
// empty. Ascending by construction because the index walks upward.
|
||||||
entry.activeBindings.clear();
|
entry.activeBindings.clear();
|
||||||
for (Uint32 binding = 0; binding < static_cast<Uint32>(entry.bindingKinds.size()); ++binding) {
|
for (Uint32 binding = 0; binding < static_cast<Uint32>(entry.bindingKinds.size()); ++binding) {
|
||||||
@@ -4128,7 +4128,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
ReflectPassthroughTessControlNeed(stages, moduleSpirvs, entry);
|
ReflectPassthroughTessControlNeed(stages, moduleSpirvs, entry);
|
||||||
ReflectLayout(program, moduleSpirvs, entry);
|
ReflectLayout(program, moduleSpirvs, entry);
|
||||||
// A failed remap means the modules kept glslang's per-stage auto-mapped binding numbers -
|
// A failed remap means the modules kept glslang's per-stage auto-mapped binding numbers -
|
||||||
// no cross-stage unification, no set->0 normalisation - so the bindings this layout
|
// no cross-stage unification, no set->0 normalization - so the bindings this layout
|
||||||
// describes are not the bindings the shader reads. That has to stop the program from
|
// describes are not the bindings the shader reads. That has to stop the program from
|
||||||
// drawing, and until now nothing did: the MOBILEGL_ASSERT above compiles out of every
|
// drawing, and until now nothing did: the MOBILEGL_ASSERT above compiles out of every
|
||||||
// build past DEBUG, and RemapDescriptorBindingsForVulkan's own refusal message said so at
|
// build past DEBUG, and RemapDescriptorBindingsForVulkan's own refusal message said so at
|
||||||
@@ -4328,7 +4328,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// PATCH_DEFAULT_OUTER_LEVEL / PATCH_DEFAULT_INNER_LEVEL state.
|
// PATCH_DEFAULT_OUTER_LEVEL / PATCH_DEFAULT_INNER_LEVEL state.
|
||||||
//
|
//
|
||||||
// Those two levels are baked in as literals - Vulkan has no equivalent dynamic state, so
|
// Those two levels are baked in as literals - Vulkan has no equivalent dynamic state, so
|
||||||
// compiling them in is the only way to honour glPatchParameterfv. That makes them part of
|
// compiling them in is the only way to honor glPatchParameterfv. That makes them part of
|
||||||
// this module's identity: GetOrCreatePassthroughTessControlStage keys its cache on them,
|
// this module's identity: GetOrCreatePassthroughTessControlStage keys its cache on them,
|
||||||
// and PipelineFactory hashes them into the pipeline key. The three must move together.
|
// and PipelineFactory hashes them into the pipeline key. The three must move together.
|
||||||
//
|
//
|
||||||
@@ -4344,7 +4344,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// this from having to know the domain.
|
// this from having to know the domain.
|
||||||
String source = "#version 450 core\n";
|
String source = "#version 450 core\n";
|
||||||
source += "layout(vertices = " + std::to_string(patchVertices) + ") out;\n";
|
source += "layout(vertices = " + std::to_string(patchVertices) + ") out;\n";
|
||||||
// gl_in and gl_out are redeclared to the exact gl_PerVertex the NEIGHBOURING EVALUATION
|
// gl_in and gl_out are redeclared to the exact gl_PerVertex the NEIGHBORING EVALUATION
|
||||||
// STAGE carries, because Vulkan matches built-in interface blocks by their whole shape,
|
// STAGE carries, because Vulkan matches built-in interface blocks by their whole shape,
|
||||||
// and the two obvious spellings are both wrong:
|
// and the two obvious spellings are both wrong:
|
||||||
// * narrowing the block to gl_Position alone makes the evaluation stage read a patch of
|
// * narrowing the block to gl_Position alone makes the evaluation stage read a patch of
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// The gl_PerVertex members a pass-through tessellation control stage may have to carry,
|
// The gl_PerVertex members a pass-through tessellation control stage may have to carry,
|
||||||
// in the order glslang declares them - which is the order a redeclaration must use.
|
// in the order glslang declares them - which is the order a redeclaration must use.
|
||||||
// Which of them exist is a function of the neighbouring stage's GLSL VERSION
|
// Which of them exist is a function of the neighboring stage's GLSL VERSION
|
||||||
// (gl_CullDistance joins the block at #version 450), so the mask is read off that
|
// (gl_CullDistance joins the block at #version 450), so the mask is read off that
|
||||||
// stage's SPIR-V rather than assumed. See ReflectPerVertexInputMembers.
|
// stage's SPIR-V rather than assumed. See ReflectPerVertexInputMembers.
|
||||||
enum class PerVertexMemberBit : Uint32 {
|
enum class PerVertexMemberBit : Uint32 {
|
||||||
@@ -647,7 +647,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// member set, because all three decide what the generator emits. The size comes from
|
// member set, because all three decide what the generator emits. The size comes from
|
||||||
// PATCH_VERTICES and the levels from PATCH_DEFAULT_OUTER_LEVEL / PATCH_DEFAULT_INNER_LEVEL
|
// PATCH_VERTICES and the levels from PATCH_DEFAULT_OUTER_LEVEL / PATCH_DEFAULT_INNER_LEVEL
|
||||||
// - draw state rather than link state, and the CTS case that motivated this links at the
|
// - draw state rather than link state, and the CTS case that motivated this links at the
|
||||||
// default 3 and draws at 4. The member set comes from the neighbouring evaluation stage's
|
// default 3 and draws at 4. The member set comes from the neighboring evaluation stage's
|
||||||
// own SPIR-V, so two programs at different GLSL versions need different modules. The
|
// own SPIR-V, so two programs at different GLSL versions need different modules. The
|
||||||
// pipeline cache re-keys on the same inputs, so the module a pipeline was built with is
|
// pipeline cache re-keys on the same inputs, so the module a pipeline was built with is
|
||||||
// part of that pipeline's identity. Compiling is bounded by the number of distinct
|
// part of that pipeline's identity. Compiling is bounded by the number of distinct
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// EGL content-validity tracking for the default framebuffer. A color
|
// EGL content-validity tracking for the default framebuffer. A color
|
||||||
// buffer's content is undefined once its image has been presented
|
// buffer's content is undefined once its image has been presented
|
||||||
// (EGL_BUFFER_DESTROYED swap behaviour, the implementation default),
|
// (EGL_BUFFER_DESTROYED swap behavior, the implementation default),
|
||||||
// and every ancillary (depth/stencil) buffer's content is undefined
|
// and every ancillary (depth/stencil) buffer's content is undefined
|
||||||
// after ANY swap regardless of swap behaviour (EGL 1.5 §3.10.1). The
|
// after ANY swap regardless of swap behavior (EGL 1.5 §3.10.1). The
|
||||||
// render-pass manager turns an undefined attachment's tile load into
|
// render-pass manager turns an undefined attachment's tile load into
|
||||||
// LOAD_OP_DONT_CARE. Flags start false (a fresh swapchain image holds
|
// LOAD_OP_DONT_CARE. Flags start false (a fresh swapchain image holds
|
||||||
// garbage) and a render pass storing into an attachment sets it back
|
// garbage) and a render pass storing into an attachment sets it back
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// submission still carries, and run_trace_case.cmake reds a split retrace on any
|
// submission still carries, and run_trace_case.cmake reds a split retrace on any
|
||||||
// "MGWIRE-FLOOR unsound-serial-complete" line, which is that fix's lane.
|
// "MGWIRE-FLOOR unsound-serial-complete" line, which is that fix's lane.
|
||||||
//
|
//
|
||||||
// THE SUBMISSION TERM IS A PROBE AND A DEFENCE, NOT A SECOND GUARANTEE. It is not sound
|
// THE SUBMISSION TERM IS A PROBE AND A DEFENSE, NOT A SECOND GUARANTEE. It is not sound
|
||||||
// on its own: lastUseSubmitIndex is stamped at AcquireWireSlice with the next submission
|
// on its own: lastUseSubmitIndex is stamped at AcquireWireSlice with the next submission
|
||||||
// index, but the draw that acquired the slice can still be pushed into a LATER
|
// index, but the draw that acquired the slice can still be pushed into a LATER
|
||||||
// submission - BindProgramUniformBuffers -> SyncWireTextureShape's preserve path ->
|
// submission - BindProgramUniformBuffers -> SyncWireTextureShape's preserve path ->
|
||||||
@@ -458,7 +458,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
} else if (busyBySerial || busyBySubmission) {
|
} else if (busyBySerial || busyBySubmission) {
|
||||||
// Vulkan buffer copies require four-byte aligned ranges. An odd GL
|
// Vulkan buffer copies require four-byte aligned ranges. An odd GL
|
||||||
// byte update waits, then writes only the exact range; rounding it
|
// byte update waits, then writes only the exact range; rounding it
|
||||||
// from a CPU shadow could overwrite neighbouring GPU-written bytes.
|
// from a CPU shadow could overwrite neighboring GPU-written bytes.
|
||||||
if (((offset | size) & 3u) == 0) {
|
if (((offset | size) & 3u) == 0) {
|
||||||
uploaded = StagedWireRangeCopy(*resource, bytes, static_cast<SizeT>(offset), static_cast<SizeT>(size));
|
uploaded = StagedWireRangeCopy(*resource, bytes, static_cast<SizeT>(offset), static_cast<SizeT>(size));
|
||||||
}
|
}
|
||||||
@@ -589,7 +589,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
// B3: the draw this slice is being acquired for is normally recorded into the NEXT
|
// B3: the draw this slice is being acquired for is normally recorded into the NEXT
|
||||||
// submission - normally, not always: a mid-draw flush (SyncWireTextureShape's preserve
|
// submission - normally, not always: a mid-draw flush (SyncWireTextureShape's preserve
|
||||||
// path) can submit this index without the draw. This stamp is the defence term's input
|
// path) can submit this index without the draw. This stamp is the defense term's input
|
||||||
// (see WriteWireBuffer); the floor behind lastUseSerial is the guarantee. Read off the
|
// (see WriteWireBuffer); the floor behind lastUseSerial is the guarantee. Read off the
|
||||||
// owning renderer's counter (its GetWireNextSubmitIndex()) when it was handed one.
|
// owning renderer's counter (its GetWireNextSubmitIndex()) when it was handed one.
|
||||||
if (m_submitCounter != nullptr)
|
if (m_submitCounter != nullptr)
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint64 size = 0;
|
Uint64 size = 0;
|
||||||
Uint64 lastUseSerial = 0;
|
Uint64 lastUseSerial = 0;
|
||||||
// P7 wave 2 package B3: the submission expected to carry the most recent GPU use
|
// P7 wave 2 package B3: the submission expected to carry the most recent GPU use
|
||||||
// of this buffer - the busy predicate's DEFENCE term, not its guarantee (see
|
// of this buffer - the busy predicate's DEFENSE term, not its guarantee (see
|
||||||
// WriteWireBuffer). IsSubmitIndexComplete polls the real fence and reports an
|
// WriteWireBuffer). IsSubmitIndexComplete polls the real fence and reports an
|
||||||
// unsubmitted index as incomplete, but the stamp is taken before the draw is
|
// unsubmitted index as incomplete, but the stamp is taken before the draw is
|
||||||
// recorded and a mid-draw flush can submit it without the draw.
|
// recorded and a mid-draw flush can submit it without the draw.
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (MG_Pipe::gPipeInputs->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)) return;
|
if (MG_Pipe::gPipeInputs->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)) return;
|
||||||
if (ResolveSrgbAttachmentWriteFormat(destinationFormat, false) == destinationFormat) return;
|
if (ResolveSrgbAttachmentWriteFormat(destinationFormat, false) == destinationFormat) return;
|
||||||
|
|
||||||
// sRGB -> linear (GL 4.6 core 8.24), applied to the colour channels only: alpha is stored
|
// sRGB -> linear (GL 4.6 core 8.24), applied to the color channels only: alpha is stored
|
||||||
// linearly in an sRGB format and must pass through untouched.
|
// linearly in an sRGB format and must pass through untouched.
|
||||||
const auto toLinear = [](Float encoded) {
|
const auto toLinear = [](Float encoded) {
|
||||||
const Float value = std::clamp(encoded, 0.0f, 1.0f);
|
const Float value = std::clamp(encoded, 0.0f, 1.0f);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 stencil{};
|
Uint32 stencil{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// A colour clear reaches us from one of glClear/ClearBufferfv, ClearBufferiv or
|
// A color clear reaches us from one of glClear/ClearBufferfv, ClearBufferiv or
|
||||||
// ClearBufferuiv, and Vulkan reads VkClearColorValue's union according to the destination
|
// ClearBufferuiv, and Vulkan reads VkClearColorValue's union according to the destination
|
||||||
// image's format rather than converting between the members - a float written where an
|
// image's format rather than converting between the members - a float written where an
|
||||||
// integer format is expected is reinterpreted bit for bit, not rounded. Remember which entry
|
// integer format is expected is reinterpreted bit for bit, not rounded. Remember which entry
|
||||||
@@ -53,7 +53,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// vkCmdClearColorImage names the image, so the driver applies the destination format's transfer
|
// vkCmdClearColorImage names the image, so the driver applies the destination format's transfer
|
||||||
// function to whatever value it is handed. Every other write path in this backend goes through
|
// function to whatever value it is handed. Every other write path in this backend goes through
|
||||||
// the UNORM twin view while GL_FRAMEBUFFER_SRGB is off (ResolveSrgbAttachmentWriteFormat) and
|
// the UNORM twin view while GL_FRAMEBUFFER_SRGB is off (ResolveSrgbAttachmentWriteFormat) and
|
||||||
// therefore stores the raw value GL asked for. Rewrites `payload` to the linear colour whose
|
// therefore stores the raw value GL asked for. Rewrites `payload` to the linear color whose
|
||||||
// encoding is that raw value, so a direct image clear of an sRGB destination agrees with them.
|
// encoding is that raw value, so a direct image clear of an sRGB destination agrees with them.
|
||||||
// A no-op for every other format, for integer clear encodings, and when GL is doing the
|
// A no-op for every other format, for integer clear encodings, and when GL is doing the
|
||||||
// encoding itself.
|
// encoding itself.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// ResolveAttachmentLayerCount lives in VkTextureManager.h, beside ToVulkanLevelExtent, because
|
// ResolveAttachmentLayerCount lives in VkTextureManager.h, beside ToVulkanLevelExtent, because
|
||||||
// VkClearManager needs the SAME answer: its pending-clear key's layerCount becomes a real
|
// VkClearManager needs the SAME answer: its pending-clear key's layerCount becomes a real
|
||||||
// VkImageSubresourceRange when a clear is materialised outside a render pass. See the header.
|
// VkImageSubresourceRange when a clear is materialized outside a render pass. See the header.
|
||||||
|
|
||||||
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(VkImageLayout trackedLayout, Bool clearDepth,
|
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(VkImageLayout trackedLayout, Bool clearDepth,
|
||||||
Bool clearStencil) {
|
Bool clearStencil) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// which std::swap(pair&, pair&) requires. That was invisible while UnorderedMap
|
// which std::swap(pair&, pair&) requires. That was invisible while UnorderedMap
|
||||||
// only ever move-CONSTRUCTED an element into a fresh slot. ska::flat_hash_map
|
// only ever move-CONSTRUCTED an element into a fresh slot. ska::flat_hash_map
|
||||||
// probes robin-hood: inserting swaps the entry being placed against the one
|
// probes robin-hood: inserting swaps the entry being placed against the one
|
||||||
// already sitting in the slot whenever it has travelled further from its desired
|
// already sitting in the slot whenever it has traveled further from its desired
|
||||||
// position, so the mapped type has to be swappable or the table fails to
|
// position, so the mapped type has to be swappable or the table fails to
|
||||||
// instantiate at all.
|
// instantiate at all.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Unsigned packed floats: no sign bit at all. 65024 is the largest 11-bit float; the
|
// Unsigned packed floats: no sign bit at all. 65024 is the largest 11-bit float; the
|
||||||
// 10-bit blue channel tops out lower (64512) and RGB9E5 higher (65408), but the bound
|
// 10-bit blue channel tops out lower (64512) and RGB9E5 higher (65408), but the bound
|
||||||
// that matters for correctness is the lower one, and a single conservative upper bound
|
// that matters for correctness is the lower one, and a single conservative upper bound
|
||||||
// costs nothing a real border colour will ever notice.
|
// costs nothing a real border color will ever notice.
|
||||||
case TextureInternalFormat::R11FG11FB10F:
|
case TextureInternalFormat::R11FG11FB10F:
|
||||||
return {true, 0.0f, 64512.0f};
|
return {true, 0.0f, 64512.0f};
|
||||||
case TextureInternalFormat::RGB9E5:
|
case TextureInternalFormat::RGB9E5:
|
||||||
@@ -152,7 +152,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Per-component representable range of an integer texture format, as Int64 so that the whole
|
// Per-component representable range of an integer texture format, as Int64 so that the whole
|
||||||
// signed and unsigned 32-bit ranges are expressible in one type and the clamp can be written
|
// signed and unsigned 32-bit ranges are expressible in one type and the clamp can be written
|
||||||
// once for both domains. Alpha is carried separately because RGB10_A2UI is the one format
|
// once for both domains. Alpha is carried separately because RGB10_A2UI is the one format
|
||||||
// whose alpha is narrower than its colour channels.
|
// whose alpha is narrower than its color channels.
|
||||||
struct IntegerBorderRange {
|
struct IntegerBorderRange {
|
||||||
Int64 rgbMin = 0;
|
Int64 rgbMin = 0;
|
||||||
Int64 rgbMax = 0;
|
Int64 rgbMax = 0;
|
||||||
@@ -360,7 +360,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
const auto compareFunc = sampler.GetSamplerCompareFunc();
|
||||||
XXHASH_VERIFY(XXH64_update(hashState, &compareFunc, sizeof(compareFunc)));
|
XXHASH_VERIFY(XXH64_update(hashState, &compareFunc, sizeof(compareFunc)));
|
||||||
// The resolved enum AND, when it is one of the *_CUSTOM_EXT values, the sixteen bytes of the
|
// The resolved enum AND, when it is one of the *_CUSTOM_EXT values, the sixteen bytes of the
|
||||||
// colour itself: two samplers that differ only in a custom border colour carry the same enum
|
// color itself: two samplers that differ only in a custom border color carry the same enum
|
||||||
// and would otherwise collide onto whichever one was created first.
|
// and would otherwise collide onto whichever one was created first.
|
||||||
XXHASH_VERIFY(XXH64_update(hashState, &borderColor.color, sizeof(borderColor.color)));
|
XXHASH_VERIFY(XXH64_update(hashState, &borderColor.color, sizeof(borderColor.color)));
|
||||||
if (borderColor.isCustom) {
|
if (borderColor.isCustom) {
|
||||||
@@ -512,14 +512,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return resolved; // FLOAT_TRANSPARENT_BLACK, never sampled
|
return resolved; // FLOAT_TRANSPARENT_BLACK, never sampled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Border colour is sampler state: a bound sampler object supplies its own, and a texture
|
// Border color is sampler state: a bound sampler object supplies its own, and a texture
|
||||||
// with none reaches the very same value through the sampler object it owns.
|
// with none reaches the very same value through the sampler object it owns.
|
||||||
const auto domain = ResolveBorderColorDomain(format);
|
const auto domain = ResolveBorderColorDomain(format);
|
||||||
const Bool canUseCustom = m_customBorderColorSupported && m_maxCustomBorderColorSamplers > 0 &&
|
const Bool canUseCustom = m_customBorderColorSupported && m_maxCustomBorderColorSamplers > 0 &&
|
||||||
m_customBorderColorSamplerCount < m_maxCustomBorderColorSamplers;
|
m_customBorderColorSamplerCount < m_maxCustomBorderColorSamplers;
|
||||||
|
|
||||||
if (domain != BorderColorDomain::Float) {
|
if (domain != BorderColorDomain::Float) {
|
||||||
// An integer image view REQUIRES an integer border colour, whatever the value is - even
|
// An integer image view REQUIRES an integer border color, whatever the value is - even
|
||||||
// (0,0,0,1). The value itself is whichever integer form the application wrote; a float
|
// (0,0,0,1). The value itself is whichever integer form the application wrote; a float
|
||||||
// border on an integer texture is nonsense GL leaves undefined, so the derived integer
|
// border on an integer texture is nonsense GL leaves undefined, so the derived integer
|
||||||
// representation (a plain cast) is as good an answer as any.
|
// representation (a plain cast) is as good an answer as any.
|
||||||
@@ -528,7 +528,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// through Int64 so the whole signed and unsigned 32-bit ranges are expressible at once.
|
// through Int64 so the whole signed and unsigned 32-bit ranges are expressible at once.
|
||||||
//
|
//
|
||||||
// Which representation to start from is the TEXTURE's domain, not the entry-point form
|
// Which representation to start from is the TEXTURE's domain, not the entry-point form
|
||||||
// the application used. GL 4.6 core 8.10 stores an "I"-form border colour unmodified with
|
// the application used. GL 4.6 core 8.10 stores an "I"-form border color unmodified with
|
||||||
// an integer internal data type and does not define a sign conversion between the two
|
// an integer internal data type and does not define a sign conversion between the two
|
||||||
// integer forms, so the stored bits are reinterpreted in the sampled format's own
|
// integer forms, so the stored bits are reinterpreted in the sampled format's own
|
||||||
// signedness. Measured, not assumed: a border of -1 written with glTexParameterIiv
|
// signedness. Measured, not assumed: a border of -1 written with glTexParameterIiv
|
||||||
@@ -578,7 +578,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
// No custom colour available: pick the nearest of the three integer palette entries
|
// No custom color available: pick the nearest of the three integer palette entries
|
||||||
// rather than always answering transparent black, which is what turned an integer border
|
// rather than always answering transparent black, which is what turned an integer border
|
||||||
// of (-1,-1,-1,-1) into 0 and broke the CTS's clamped-texel detection outright.
|
// of (-1,-1,-1,-1) into 0 and broke the CTS's clamped-texel detection outright.
|
||||||
const Bool opaque = clamped[3] != 0;
|
const Bool opaque = clamped[3] != 0;
|
||||||
@@ -588,7 +588,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float domain. GL 4.6 core 8.14.2/8.23: the border colour is interpreted in the texture's
|
// Float domain. GL 4.6 core 8.14.2/8.23: the border color is interpreted in the texture's
|
||||||
// format, so it is clamped to that format's representable range first. Without the clamp the
|
// format, so it is clamped to that format's representable range first. Without the clamp the
|
||||||
// CTS's border of (255,255,255,255) on a GL_RGBA8 texture matched none of the palette entries
|
// CTS's border of (255,255,255,255) on a GL_RGBA8 texture matched none of the palette entries
|
||||||
// and fell through to transparent black - every border texel sampled 0 where the test wanted
|
// and fell through to transparent black - every border texel sampled 0 where the test wanted
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// customBorderColorWithoutFormat; see VulkanRenderer::m_customBorderColorFeatureEnabled.
|
// customBorderColorWithoutFormat; see VulkanRenderer::m_customBorderColorFeatureEnabled.
|
||||||
Bool customBorderColorSupported = false;
|
Bool customBorderColorSupported = false;
|
||||||
// VkPhysicalDeviceCustomBorderColorPropertiesEXT::maxCustomBorderColorSamplers. A hard device
|
// VkPhysicalDeviceCustomBorderColorPropertiesEXT::maxCustomBorderColorSamplers. A hard device
|
||||||
// limit on how many LIVE samplers may carry a custom border colour, so the cache counts them
|
// limit on how many LIVE samplers may carry a custom border color, so the cache counts them
|
||||||
// and falls back to the snapped predefined value once it is reached.
|
// and falls back to the snapped predefined value once it is reached.
|
||||||
Uint32 maxCustomBorderColorSamplers = 0;
|
Uint32 maxCustomBorderColorSamplers = 0;
|
||||||
};
|
};
|
||||||
@@ -70,7 +70,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Resolved ONCE per GetOrCreateSampler call and threaded into both the cache key and the
|
// Resolved ONCE per GetOrCreateSampler call and threaded into both the cache key and the
|
||||||
// create-info, so the two cannot disagree - the same discipline the resolved anisotropy needs,
|
// create-info, so the two cannot disagree - the same discipline the resolved anisotropy needs,
|
||||||
// and here it also makes the maxCustomBorderColorSamplers fallback deterministic: whether a
|
// and here it also makes the maxCustomBorderColorSamplers fallback deterministic: whether a
|
||||||
// custom colour was affordable is decided before the key is built, not twice with a budget
|
// custom color was affordable is decided before the key is built, not twice with a budget
|
||||||
// change in between.
|
// change in between.
|
||||||
struct ResolvedBorderColor {
|
struct ResolvedBorderColor {
|
||||||
VkBorderColor color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
VkBorderColor color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
@@ -115,7 +115,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Float m_maxSamplerAnisotropy = 1.0f;
|
Float m_maxSamplerAnisotropy = 1.0f;
|
||||||
Bool m_customBorderColorSupported = false;
|
Bool m_customBorderColorSupported = false;
|
||||||
Uint32 m_maxCustomBorderColorSamplers = 0;
|
Uint32 m_maxCustomBorderColorSamplers = 0;
|
||||||
// Live cache entries carrying a custom border colour. Kept in step with the entries themselves
|
// Live cache entries carrying a custom border color. Kept in step with the entries themselves
|
||||||
// in exactly the three places one can appear or disappear: creation, the OnFrameBoundary sweep,
|
// in exactly the three places one can appear or disappear: creation, the OnFrameBoundary sweep,
|
||||||
// and Shutdown.
|
// and Shutdown.
|
||||||
Uint32 m_customBorderColorSamplerCount = 0;
|
Uint32 m_customBorderColorSamplerCount = 0;
|
||||||
|
|||||||
@@ -732,7 +732,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// TryResolveTextureShapeInfo's answers derived from the wire descriptor instead of the
|
// TryResolveTextureShapeInfo's answers derived from the wire descriptor instead of the
|
||||||
// frontend object. The descriptor's Width/Height/Depth are the BASE level's GL extent and
|
// frontend object. The descriptor's Width/Height/Depth are the BASE level's GL extent and
|
||||||
// ArrayLayers the layer count the emitter already normalised (MGPipeTextureExtentOf: a 1D
|
// ArrayLayers the layer count the emitter already normalized (MGPipeTextureExtentOf: a 1D
|
||||||
// array's layers are already out of its height, a cube map reports 6).
|
// array's layers are already out of its height, a cube map reports 6).
|
||||||
static Bool ResolveWireTextureShapeInfo(const MG_Pipe::MGPResourceDesc& desc, TextureShapeInfo& outShape) {
|
static Bool ResolveWireTextureShapeInfo(const MG_Pipe::MGPResourceDesc& desc, TextureShapeInfo& outShape) {
|
||||||
using MG_Pipe::MGPipeResourceTarget;
|
using MG_Pipe::MGPipeResourceTarget;
|
||||||
@@ -768,7 +768,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
outShape.arrayLayers = 6;
|
outShape.arrayLayers = 6;
|
||||||
return desc.Width > 0 && desc.Width == desc.Height;
|
return desc.Width > 0 && desc.Width == desc.Height;
|
||||||
case MGPipeResourceTarget::TexCubeArray:
|
case MGPipeResourceTarget::TexCubeArray:
|
||||||
// glTexStorage3D hands 6n through as the depth; the emitter normalised it into
|
// glTexStorage3D hands 6n through as the depth; the emitter normalized it into
|
||||||
// ArrayLayers. A non-whole cube count has no Vulkan shape - declined like every
|
// ArrayLayers. A non-whole cube count has no Vulkan shape - declined like every
|
||||||
// other unrepresentable target.
|
// other unrepresentable target.
|
||||||
outShape.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
outShape.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
||||||
@@ -1706,7 +1706,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// The RGBA8/RGBX8 buffers the registry allocates have a Vulkan format; an external-only
|
// The RGBA8/RGBX8 buffers the registry allocates have a Vulkan format; an external-only
|
||||||
// format would need a YCbCr conversion and is not a colour buffer this path can write.
|
// format would need a YCbCr conversion and is not a color buffer this path can write.
|
||||||
if (formatProperties.format == VK_FORMAT_UNDEFINED) {
|
if (formatProperties.format == VK_FORMAT_UNDEFINED) {
|
||||||
why = "the buffer has no Vulkan format (external format only)";
|
why = "the buffer has no Vulkan format (external format only)";
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -84,9 +84,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// again in VkClearManager.cpp - and the two are not independent: the render pass builds the
|
// again in VkClearManager.cpp - and the two are not independent: the render pass builds the
|
||||||
// attachment view and VkFramebufferCreateInfo::layers from one, while the CLEAR key built from the
|
// attachment view and VkFramebufferCreateInfo::layers from one, while the CLEAR key built from the
|
||||||
// other is written verbatim into VkImageSubresourceRange::layerCount when a queued glClear is
|
// other is written verbatim into VkImageSubresourceRange::layerCount when a queued glClear is
|
||||||
// materialised outside a render pass (MaterializePendingClearForTexture). They are two consumers
|
// materialized outside a render pass (MaterializePendingClearForTexture). They are two consumers
|
||||||
// of the same GL clear, so any disagreement means the same glClear produces two different pictures
|
// of the same GL clear, so any disagreement means the same glClear produces two different pictures
|
||||||
// depending only on which path happens to consume it first - and the materialise path then POPS
|
// depending only on which path happens to consume it first - and the materialize path then POPS
|
||||||
// the entry, so the other one never runs. Fixing one copy and leaving the other is exactly how
|
// the entry, so the other one never runs. Fixing one copy and leaving the other is exactly how
|
||||||
// that split gets introduced; keep them the same function.
|
// that split gets introduced; keep them the same function.
|
||||||
//
|
//
|
||||||
@@ -586,7 +586,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 layerCount = 1);
|
Uint32 layerCount = 1);
|
||||||
|
|
||||||
// SHARED IMAGES: a server shared image's
|
// SHARED IMAGES: a server shared image's
|
||||||
// AHardwareBuffer bound as a single-level 2D colour image on THIS session's device, on dedicated
|
// AHardwareBuffer bound as a single-level 2D color image on THIS session's device, on dedicated
|
||||||
// memory imported from the buffer. Android only (false with `why` elsewhere, or when the device
|
// memory imported from the buffer. Android only (false with `why` elsewhere, or when the device
|
||||||
// did not take the AHardwareBuffer extension). The image is born UNDEFINED; whoever uses it
|
// did not take the AHardwareBuffer extension). The image is born UNDEFINED; whoever uses it
|
||||||
// acquires it from the foreign queue family first, and a writer releases it back after.
|
// acquires it from the foreign queue family first, and a writer releases it back after.
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// `defaultFramebufferOrientation` is set only when the source is the swapchain's
|
// `defaultFramebufferOrientation` is set only when the source is the swapchain's
|
||||||
// depth/stencil image, which this renderer stores display-side-up: the copy rect then
|
// depth/stencil image, which this renderer stores display-side-up: the copy rect then
|
||||||
// has to be mapped out of GL's bottom-origin space and the copied rows re-oriented on
|
// has to be mapped out of GL's bottom-origin space and the copied rows re-oriented on
|
||||||
// the way back, exactly as the colour ReadPixels path does.
|
// the way back, exactly as the color ReadPixels path does.
|
||||||
// `sourceLayerCount` above 1 says the `height` rows the client is owed are stored as that
|
// `sourceLayerCount` above 1 says the `height` rows the client is owed are stored as that
|
||||||
// many ARRAY LAYERS of a one-row image rather than as rows of one layer - the shape a GL
|
// many ARRAY LAYERS of a one-row image rather than as rows of one layer - the shape a GL
|
||||||
// 1D array has in Vulkan. The two produce byte-identical tightly-packed readbacks, so
|
// 1D array has in Vulkan. The two produce byte-identical tightly-packed readbacks, so
|
||||||
@@ -651,7 +651,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// and the default draw framebuffer alike. The CAPABILITY decline inside
|
// and the default draw framebuffer alike. The CAPABILITY decline inside
|
||||||
// ResolveWireDepthStencil (a stencil-only resolve without VK_EXT_shader_stencil_export
|
// ResolveWireDepthStencil (a stencil-only resolve without VK_EXT_shader_stencil_export
|
||||||
// on a device without VK_KHR_depth_stencil_resolve) is still decided per aspect, after
|
// on a device without VK_KHR_depth_stencil_resolve) is still decided per aspect, after
|
||||||
// colour ran; rule I (a) accepts that (§2.10).
|
// color ran; rule I (a) accepts that (§2.10).
|
||||||
Bool DeclineWireDepthStencilResolveShape(const WireImage& source, const WireImage& destination, GLint sx0,
|
Bool DeclineWireDepthStencilResolveShape(const WireImage& source, const WireImage& destination, GLint sx0,
|
||||||
GLint sy0, GLint sx1, GLint sy1, GLint dx0, GLint dy0, GLint dx1,
|
GLint sy0, GLint sx1, GLint sy1, GLint dx0, GLint dy0, GLint dx1,
|
||||||
GLint dy1);
|
GLint dy1);
|
||||||
@@ -682,7 +682,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool m_wireAhbImport = false;
|
Bool m_wireAhbImport = false;
|
||||||
void* m_wireGetAhbProperties = nullptr;
|
void* m_wireGetAhbProperties = nullptr;
|
||||||
// YUV shared images (WireYuvImage.cpp): the device enabled samplerYcbcrConversion, and the
|
// YUV shared images (WireYuvImage.cpp): the device enabled samplerYcbcrConversion, and the
|
||||||
// conversion pipelines made so far (one per buffer format and colour conversion).
|
// conversion pipelines made so far (one per buffer format and color conversion).
|
||||||
Bool m_samplerYcbcrConversion = false;
|
Bool m_samplerYcbcrConversion = false;
|
||||||
struct WireYuvResources;
|
struct WireYuvResources;
|
||||||
WireYuvResources* m_wireYuvResources = nullptr;
|
WireYuvResources* m_wireYuvResources = nullptr;
|
||||||
@@ -704,7 +704,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
UnorderedMap<Uint64, SharedImagePresentTarget> m_sharedImagePresentTargets;
|
UnorderedMap<Uint64, SharedImagePresentTarget> m_sharedImagePresentTargets;
|
||||||
void DestroySharedImagePresentTargets(Bool onlyDead);
|
void DestroySharedImagePresentTargets(Bool onlyDead);
|
||||||
|
|
||||||
// SHARED-IMAGE SYNCHRONISATION (WireSharedImage.cpp). The sync_file fences other sessions
|
// SHARED-IMAGE SYNCHRONIZATION (WireSharedImage.cpp). The sync_file fences other sessions
|
||||||
// publish become binary semaphores: a temporary SYNC_FD import is a WAIT, an exportable
|
// publish become binary semaphores: a temporary SYNC_FD import is a WAIT, an exportable
|
||||||
// semaphore a SIGNAL, of the next frame submission - whichever of SubmitPendingCommandBuffer
|
// semaphore a SIGNAL, of the next frame submission - whichever of SubmitPendingCommandBuffer
|
||||||
// and Present's submit comes first, which is the one carrying what was recorded since.
|
// and Present's submit comes first, which is the one carrying what was recorded since.
|
||||||
@@ -1185,9 +1185,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// VK_EXT_custom_border_color. Vulkan's four predefined VkBorderColor values cover only
|
// VK_EXT_custom_border_color. Vulkan's four predefined VkBorderColor values cover only
|
||||||
// transparent/opaque black and opaque white; GL_TEXTURE_BORDER_COLOR is an arbitrary vec4 (or
|
// transparent/opaque black and opaque white; GL_TEXTURE_BORDER_COLOR is an arbitrary vec4 (or
|
||||||
// an arbitrary ivec4/uvec4 through the "I" entry points). Without this extension a border
|
// an arbitrary ivec4/uvec4 through the "I" entry points). Without this extension a border
|
||||||
// colour outside the palette has to be snapped to the nearest predefined one. Both features
|
// color outside the palette has to be snapped to the nearest predefined one. Both features
|
||||||
// are required together: customBorderColorWithoutFormat is what lets a sampler carry a custom
|
// are required together: customBorderColorWithoutFormat is what lets a sampler carry a custom
|
||||||
// colour without naming the image format it will be paired with, which GL's sampler objects
|
// color without naming the image format it will be paired with, which GL's sampler objects
|
||||||
// cannot know. maxCustomBorderColorSamplers is a real device limit, so the sampler cache has
|
// cannot know. maxCustomBorderColorSamplers is a real device limit, so the sampler cache has
|
||||||
// to be able to fall back to the snapped value once it is reached.
|
// to be able to fall back to the snapped value once it is reached.
|
||||||
Bool m_customBorderColorFeatureEnabled = false;
|
Bool m_customBorderColorFeatureEnabled = false;
|
||||||
@@ -1249,7 +1249,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// pipeline from asking for LAST on a device that cannot preserve a fan's provoking vertex.
|
// pipeline from asking for LAST on a device that cannot preserve a fan's provoking vertex.
|
||||||
Bool m_provokingVertexXfbPreserveEnabled = false;
|
Bool m_provokingVertexXfbPreserveEnabled = false;
|
||||||
// provokingVertexModePerPipeline: when VK_FALSE every pipeline in one render pass instance
|
// provokingVertexModePerPipeline: when VK_FALSE every pipeline in one render pass instance
|
||||||
// must agree on the mode, so glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) cannot be honoured
|
// must agree on the mode, so glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) cannot be honored
|
||||||
// per draw and every pipeline takes GL's default (LAST) instead.
|
// per draw and every pipeline takes GL's default (LAST) instead.
|
||||||
Bool m_provokingVertexModePerPipeline = false;
|
Bool m_provokingVertexModePerPipeline = false;
|
||||||
// transformFeedbackPreservesTriangleFanProvokingVertex.
|
// transformFeedbackPreservesTriangleFanProvokingVertex.
|
||||||
|
|||||||
@@ -726,11 +726,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Nothing else on this path asks: the three checks around it cover the mip range, the region
|
// Nothing else on this path asks: the three checks around it cover the mip range, the region
|
||||||
// bounds and the slice range, and none of them ever looked at a format.
|
// bounds and the slice range, and none of them ever looked at a format.
|
||||||
//
|
//
|
||||||
// A decline rather than a MOBILEGL_ASSERT, for the reason the neighbouring guards spell out:
|
// A decline rather than a MOBILEGL_ASSERT, for the reason the neighboring guards spell out:
|
||||||
// assertions compile out of the release build that the CTS and shipping both run, which is
|
// assertions compile out of the release build that the CTS and shipping both run, which is
|
||||||
// exactly where the corruption was observed.
|
// exactly where the corruption was observed.
|
||||||
if (srcImage.format != dstImage.format) {
|
if (srcImage.format != dstImage.format) {
|
||||||
// Size-compatibility is the COLOUR rule. Vulkan makes each depth/stencil format compatible
|
// Size-compatibility is the COLOR rule. Vulkan makes each depth/stencil format compatible
|
||||||
// only with ITSELF, and the texel block sizes cannot tell them apart: X8_D24_UNORM_PACK32,
|
// only with ITSELF, and the texel block sizes cannot tell them apart: X8_D24_UNORM_PACK32,
|
||||||
// D32_SFLOAT and D24_UNORM_S8_UINT are all 4 bytes and all in different compatibility
|
// D32_SFLOAT and D24_UNORM_S8_UINT are all 4 bytes and all in different compatibility
|
||||||
// classes, so a raw block-size test waves through exactly the pairs Vulkan forbids. The
|
// classes, so a raw block-size test waves through exactly the pairs Vulkan forbids. The
|
||||||
@@ -1419,9 +1419,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, imageAspect, mipLevel, 1);
|
VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, imageAspect, mipLevel, 1);
|
||||||
MOBILEGL_ASSERT(ok, "%s: failed to transition depth-stencil source image", __func__);
|
MOBILEGL_ASSERT(ok, "%s: failed to transition depth-stencil source image", __func__);
|
||||||
|
|
||||||
// The swapchain's depth/stencil image is stored display-side-up like its colour twin, so
|
// The swapchain's depth/stencil image is stored display-side-up like its color twin, so
|
||||||
// the GL rect has to be mapped into that space before the copy and the copied rows
|
// the GL rect has to be mapped into that space before the copy and the copied rows
|
||||||
// re-oriented afterwards - the same two halves the colour ReadPixels path applies.
|
// re-oriented afterwards - the same two halves the color ReadPixels path applies.
|
||||||
VkOffset2D copyOffset{x, y};
|
VkOffset2D copyOffset{x, y};
|
||||||
VkExtent2D copyExtent{static_cast<Uint32>(width), static_cast<Uint32>(height)};
|
VkExtent2D copyExtent{static_cast<Uint32>(width), static_cast<Uint32>(height)};
|
||||||
if (defaultFramebufferOrientation) {
|
if (defaultFramebufferOrientation) {
|
||||||
|
|||||||
@@ -755,7 +755,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// P11 B2 (T0): a client's AHardwareBuffer imported as a wire buffer store. Wire arms, on
|
// P11 B2 (T0): a client's AHardwareBuffer imported as a wire buffer store. Wire arms, on
|
||||||
// Android, whenever the device advertises the extension - not per session: the device is
|
// Android, whenever the device advertises the extension - not per session: the device is
|
||||||
// created once per server and a later session asking T0 must find it able. Enabling it
|
// created once per server and a later session asking T0 must find it able. Enabling it
|
||||||
// changes no T2 behaviour; only an import uses it. The 1.0-era dependencies are core at the
|
// changes no T2 behavior; only an import uses it. The 1.0-era dependencies are core at the
|
||||||
// 1.1 this device is created at, and are enabled too when advertised (the spike's set).
|
// 1.1 this device is created at, and are enabled too when advertised (the spike's set).
|
||||||
m_wireAhbImport = false;
|
m_wireAhbImport = false;
|
||||||
m_wireGetAhbProperties = nullptr;
|
m_wireGetAhbProperties = nullptr;
|
||||||
@@ -943,7 +943,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// an integer border of -1 come back as 0.
|
// an integer border of -1 come back as 0.
|
||||||
//
|
//
|
||||||
// customBorderColorWithoutFormat is required alongside customBorderColors, not merely
|
// customBorderColorWithoutFormat is required alongside customBorderColors, not merely
|
||||||
// preferred: a GL sampler object carries a border colour with no idea which texture it will
|
// preferred: a GL sampler object carries a border color with no idea which texture it will
|
||||||
// be paired with, so the VkSamplerCustomBorderColorCreateInfoEXT this backend builds has to
|
// be paired with, so the VkSamplerCustomBorderColorCreateInfoEXT this backend builds has to
|
||||||
// leave `format` VK_FORMAT_UNDEFINED.
|
// leave `format` VK_FORMAT_UNDEFINED.
|
||||||
m_customBorderColorFeatureEnabled = false;
|
m_customBorderColorFeatureEnabled = false;
|
||||||
@@ -987,7 +987,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Native subgroup topology, and VK_EXT_subgroup_size_control's
|
// Native subgroup topology, and VK_EXT_subgroup_size_control's
|
||||||
// computeFullSubgroups feature. REQUIRE_FULL_SUBGROUPS on a compute stage is what
|
// computeFullSubgroups feature. REQUIRE_FULL_SUBGROUPS on a compute stage is what
|
||||||
// turns the derived gl_NumSubgroups (DeriveNumSubgroupsPass) from
|
// turns the derived gl_NumSubgroups (DeriveNumSubgroupsPass) from
|
||||||
// encouraged-but-unspecified driver behaviour into a spec guarantee: with the bit
|
// encouraged-but-unspecified driver behavior into a spec guarantee: with the bit
|
||||||
// set and local_size_x a multiple of the subgroup size, every subgroup launches
|
// set and local_size_x a multiple of the subgroup size, every subgroup launches
|
||||||
// full, so the subgroup count is exactly invocations / size ("Full Subgroups",
|
// full, so the subgroup count is exactly invocations / size ("Full Subgroups",
|
||||||
// VUID-VkPipelineShaderStageCreateInfo-flags-02759/-02785).
|
// VUID-VkPipelineShaderStageCreateInfo-flags-02759/-02785).
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// end up with a module carrying no Xfb mode - the clip/XFB validation backstop rewinding
|
// end up with a module carrying no Xfb mode - the clip/XFB validation backstop rewinding
|
||||||
// past the decoration, or XfbCaptureDecoratePass resolving none of the requested varyings
|
// past the decoration, or XfbCaptureDecoratePass resolving none of the requested varyings
|
||||||
// and changing nothing. Declining the span leaves the capture buffers untouched, which is
|
// and changing nothing. Declining the span leaves the capture buffers untouched, which is
|
||||||
// the same nothing the driver would have written, without the undefined behaviour.
|
// the same nothing the driver would have written, without the undefined behavior.
|
||||||
if (m_currentDrawXfbCaptureDeclined) {
|
if (m_currentDrawXfbCaptureDeclined) {
|
||||||
MGLOG_E_ONCE("BeginXfbCaptureForDraw: declining the capture span - the bound program's last "
|
MGLOG_E_ONCE("BeginXfbCaptureForDraw: declining the capture span - the bound program's last "
|
||||||
"pre-rasterization stage carries no Xfb execution mode, so recording one would be "
|
"pre-rasterization stage carries no Xfb execution mode, so recording one would be "
|
||||||
"undefined behaviour rather than a capture");
|
"undefined behavior rather than a capture");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return BeginWireXfbCaptureForDraw(frame);
|
return BeginWireXfbCaptureForDraw(frame);
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
//
|
//
|
||||||
// Rectangles were never converted. The viewport, the scissor and the ReadPixels copy offset
|
// Rectangles were never converted. The viewport, the scissor and the ReadPixels copy offset
|
||||||
// all used the GL bottom-origin Y verbatim as a Vulkan top-origin Y, which is correct only
|
// all used the GL bottom-origin Y verbatim as a Vulkan top-origin Y, which is correct only
|
||||||
// when y == H - y - h (full height, or vertically centred) - and full height is the only case
|
// when y == H - y - h (full height, or vertically centered) - and full height is the only case
|
||||||
// any test ever exercised. In the conformance suite the errors CANCEL in placement (the draw
|
// any test ever exercised. In the conformance suite the errors CANCEL in placement (the draw
|
||||||
// lands in Vulkan rows [y, y+h) and the readback copies the same rows back) and compose into
|
// lands in Vulkan rows [y, y+h) and the readback copies the same rows back) and compose into
|
||||||
// an exact vertical flip: 1,759 of Magma's 1,793 non-passing cases, 861 vertical flips and
|
// an exact vertical flip: 1,759 of Magma's 1,793 non-passing cases, 861 vertical flips and
|
||||||
@@ -155,7 +155,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// The GL viewport rect, expressed against the default framebuffer's stored orientation.
|
// The GL viewport rect, expressed against the default framebuffer's stored orientation.
|
||||||
// A full-height viewport is unchanged by this, which is why every existing scenario keeps
|
// A full-height viewport is unchanged by this, which is why every existing scenario keeps
|
||||||
// its exact behaviour.
|
// its exact behavior.
|
||||||
if (isDefaultFramebuffer) {
|
if (isDefaultFramebuffer) {
|
||||||
const DefaultFramebufferRectMapping mapping = GetDefaultFramebufferRectMapping(preTransform);
|
const DefaultFramebufferRectMapping mapping = GetDefaultFramebufferRectMapping(preTransform);
|
||||||
viewportX = MapDefaultFramebufferRectAxis(viewportX, viewportWidth, framebufferExtent.x(), mapping.mirrorX);
|
viewportX = MapDefaultFramebufferRectAxis(viewportX, viewportWidth, framebufferExtent.x(), mapping.mirrorX);
|
||||||
@@ -338,7 +338,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
static_cast<Uint32>(std::max<Int>(0, rawY1 - rawY0)),
|
static_cast<Uint32>(std::max<Int>(0, rawY1 - rawY0)),
|
||||||
};
|
};
|
||||||
// A quarter turn maps to {false, false}, so this is a no-op today; it is here so the
|
// A quarter turn maps to {false, false}, so this is a no-op today; it is here so the
|
||||||
// branch cannot drift away from the identity/180 one when quarter turns are modelled.
|
// branch cannot drift away from the identity/180 one when quarter turns are modeled.
|
||||||
return MapScissorRectToDefaultFramebuffer(scissor, framebufferExtent, preTransform);
|
return MapScissorRectToDefaultFramebuffer(scissor, framebufferExtent, preTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,8 +670,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// - patch vertices, polygon mode, cull face mode, depth func, logic op,
|
// - patch vertices, polygon mode, cull face mode, depth func, logic op,
|
||||||
// min sample shading, the glSampleMaski word
|
// min sample shading, the glSampleMaski word
|
||||||
// - front/back stencil ops + compare funcs (ref/mask are dynamic state)
|
// - front/back stencil ops + compare funcs (ref/mask are dynamic state)
|
||||||
// - per draw buffer up to the render pass's colour span: indexed blend enable,
|
// - per draw buffer up to the render pass's color span: indexed blend enable,
|
||||||
// blend factors/equations, indexed colour write mask (broadcast from index 0
|
// blend factors/equations, indexed color write mask (broadcast from index 0
|
||||||
// when the device lacks independentBlend - the same read the payload does)
|
// when the device lacks independentBlend - the same read the payload does)
|
||||||
// FBO-derived payload inputs (attachment presence/formats/draw-buffer gating) are
|
// FBO-derived payload inputs (attachment presence/formats/draw-buffer gating) are
|
||||||
// pinned by the render-pass hash key, exactly as the version-keyed memo relied on.
|
// pinned by the render-pass hash key, exactly as the version-keyed memo relied on.
|
||||||
@@ -1078,7 +1078,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// is an OVER-count, which breaks the lower-bound contract every other tally keeps.
|
// is an OVER-count, which breaks the lower-bound contract every other tally keeps.
|
||||||
//
|
//
|
||||||
// The 15 are: the six capability reads (cull face, depth test, polygon offset
|
// The 15 are: the six capability reads (cull face, depth test, polygon offset
|
||||||
// fill, rasterizer discard, colour logic op, stencil test), the draw-FBO slot
|
// fill, rasterizer discard, color logic op, stencil test), the draw-FBO slot
|
||||||
// read that gates depth/stencil, the two stencil face states, the polygon mode,
|
// read that gates depth/stencil, the two stencil face states, the polygon mode,
|
||||||
// the min sample shading value, the patch vertex count, the depth mask, the depth
|
// the min sample shading value, the patch vertex count, the depth mask, the depth
|
||||||
// func, and the second draw-FBO slot read below. The sample-shading CAPABILITY
|
// func, and the second draw-FBO slot read below. The sample-shading CAPABILITY
|
||||||
@@ -1103,7 +1103,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
.sampleShadingEnable = m_sampleRateShadingFeatureEnabled &&
|
.sampleShadingEnable = m_sampleRateShadingFeatureEnabled &&
|
||||||
MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::SampleShading),
|
MG_Pipe::gPipeInputs->IsCapabilityEnabled(CapabilityInput::SampleShading),
|
||||||
.minSampleShading = MG_Pipe::gPipeInputs->GetMinSampleShadingValue(),
|
.minSampleShading = MG_Pipe::gPipeInputs->GetMinSampleShadingValue(),
|
||||||
// Word 1 keeps its all-ones initialiser: GL has no state for samples 32..63.
|
// Word 1 keeps its all-ones initializer: GL has no state for samples 32..63.
|
||||||
.sampleMask = {ResolveEffectiveSampleMask(renderPassEntry.sampleCount), 0xffffffffu},
|
.sampleMask = {ResolveEffectiveSampleMask(renderPassEntry.sampleCount), 0xffffffffu},
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.topology = vkTopology,
|
.topology = vkTopology,
|
||||||
@@ -1121,7 +1121,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// over the same rows), and a Y-negated position - the default framebuffer's flip or
|
// over the same rows), and a Y-negated position - the default framebuffer's flip or
|
||||||
// an upper-left clip origin - reverses the winding once more. Expressed as the front
|
// an upper-left clip origin - reverses the winding once more. Expressed as the front
|
||||||
// face rather than as swapped cull bits so gl_FrontFacing agrees with culling, and
|
// face rather than as swapped cull bits so gl_FrontFacing agrees with culling, and
|
||||||
// so glFrontFace(GL_CW) is honoured.
|
// so glFrontFace(GL_CW) is honored.
|
||||||
.frontFace = ((MG_Pipe::gPipeInputs->GetRenderStateParameters().FrontFaceModeSetting ==
|
.frontFace = ((MG_Pipe::gPipeInputs->GetRenderStateParameters().FrontFaceModeSetting ==
|
||||||
FrontFaceMode::Clockwise) != invertClockwise)
|
FrontFaceMode::Clockwise) != invertClockwise)
|
||||||
? VK_FRONT_FACE_COUNTER_CLOCKWISE
|
? VK_FRONT_FACE_COUNTER_CLOCKWISE
|
||||||
@@ -1164,7 +1164,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// attached and CreatePipeline refuses the pipeline, which skips the draw.
|
// attached and CreatePipeline refuses the pipeline, which skips the draw.
|
||||||
//
|
//
|
||||||
// Gated on the PATCH topology as well, and that gate is load-bearing rather than an
|
// Gated on the PATCH topology as well, and that gate is load-bearing rather than an
|
||||||
// optimisation: patchControlPoints is only meaningful for a patch draw, and a pipeline
|
// optimization: patchControlPoints is only meaningful for a patch draw, and a pipeline
|
||||||
// that carries tessellation stages while its topology is anything else violates
|
// that carries tessellation stages while its topology is anything else violates
|
||||||
// VUID-VkGraphicsPipelineCreateInfo-topology-00737 - the same class of invalid input as
|
// VUID-VkGraphicsPipelineCreateInfo-topology-00737 - the same class of invalid input as
|
||||||
// the missing control stage, on the same driver. Such a draw is illegal in GL too (a
|
// the missing control stage, on the same driver. Such a draw is illegal in GL too (a
|
||||||
@@ -1217,7 +1217,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
payload.backStencilCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
}
|
}
|
||||||
const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask;
|
const Uint32 fragmentOutputMask = programObj.activeFragmentOutputLocationMask;
|
||||||
// Outputs at locations past the render pass's trimmed colour span are
|
// Outputs at locations past the render pass's trimmed color span are
|
||||||
// simply discarded - GL's semantic for a fragment output whose draw
|
// simply discarded - GL's semantic for a fragment output whose draw
|
||||||
// buffer is GL_NONE (the trailing UNUSED slots no longer occupy
|
// buffer is GL_NONE (the trailing UNUSED slots no longer occupy
|
||||||
// references, see GetOrCreateRenderPass).
|
// references, see GetOrCreateRenderPass).
|
||||||
@@ -1340,7 +1340,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-00608 and its three
|
// VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-00608 and its three
|
||||||
// siblings forbid a VK_BLEND_FACTOR_SRC1_* in the struct without the feature whatever
|
// siblings forbid a VK_BLEND_FACTOR_SRC1_* in the struct without the feature whatever
|
||||||
// blendEnable says, so clearing only the enable would still be invalid pipeline state.
|
// blendEnable says, so clearing only the enable would still be invalid pipeline state.
|
||||||
// The previous behaviour, throwing, took the whole process down over one unsupported
|
// The previous behavior, throwing, took the whole process down over one unsupported
|
||||||
// blend factor; this is defined, survivable and visible in the log, and it matches what
|
// blend factor; this is defined, survivable and visible in the log, and it matches what
|
||||||
// the non-blendable-format arm above already does.
|
// the non-blendable-format arm above already does.
|
||||||
if (!m_dualSrcBlendFeatureEnabled &&
|
if (!m_dualSrcBlendFeatureEnabled &&
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_VERIFY(result, "Present, vkQueuePresentKHR");
|
VK_VERIFY(result, "Present, vkQueuePresentKHR");
|
||||||
// EGL swap semantics: the presented color buffer's content is undefined the
|
// EGL swap semantics: the presented color buffer's content is undefined the
|
||||||
// next time this image is acquired (EGL_BUFFER_DESTROYED, the default swap
|
// next time this image is acquired (EGL_BUFFER_DESTROYED, the default swap
|
||||||
// behaviour), and EVERY ancillary depth/stencil buffer's content is
|
// behavior), and EVERY ancillary depth/stencil buffer's content is
|
||||||
// undefined after any swap. The render-pass manager turns the undefined
|
// undefined after any swap. The render-pass manager turns the undefined
|
||||||
// attachments' next tile loads into LOAD_OP_DONT_CARE.
|
// attachments' next tile loads into LOAD_OP_DONT_CARE.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// The floor now advances only to a serial NO remaining in-flight submission still
|
// The floor now advances only to a serial NO remaining in-flight submission still
|
||||||
// carries. NotifyFrameSerialComplete is monotone and already refuses the still-
|
// carries. NotifyFrameSerialComplete is monotone and already refuses the still-
|
||||||
// recording serial, so this can only ever advance the floor later, never further.
|
// recording serial, so this can only ever advance the floor later, never further.
|
||||||
// On the disaggregated build's MONOLITH arm this is behaviour-identical (one
|
// On the disaggregated build's MONOLITH arm this is behavior-identical (one
|
||||||
// submission per serial). The #else branch below is the pull build's statement,
|
// submission per serial). The #else branch below is the pull build's statement,
|
||||||
// unchanged, which is what keeps G1's .text byte-identical.
|
// unchanged, which is what keeps G1's .text byte-identical.
|
||||||
Bool retiredAny = false;
|
Bool retiredAny = false;
|
||||||
@@ -707,7 +707,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
// Only provokingVertexModePerPipeline lets modes differ inside one render pass instance;
|
// Only provokingVertexModePerPipeline lets modes differ inside one render pass instance;
|
||||||
// elsewhere every pipeline takes GL's default so the render pass stays self-consistent, and
|
// elsewhere every pipeline takes GL's default so the render pass stays self-consistent, and
|
||||||
// glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) goes unhonoured. Honouring it there would
|
// glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) goes unhonoured. Honoring it there would
|
||||||
// mean ending the render pass on every glProvokingVertex change; not worth it until a target
|
// mean ending the render pass on every glProvokingVertex change; not worth it until a target
|
||||||
// device actually lacks the property.
|
// device actually lacks the property.
|
||||||
if (!m_provokingVertexModePerPipeline) {
|
if (!m_provokingVertexModePerPipeline) {
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// P7 wave 2-B (CONTRACT-P7 §3.2, `default-color-blit-shape`). The shader blit below can only
|
// P7 wave 2-B (CONTRACT-P7 §3.2, `default-color-blit-shape`). The shader blit below can only
|
||||||
// SAMPLE its source: sampler2D, a float result, and one of two 2D view types. A framebuffer
|
// SAMPLE its source: sampler2D, a float result, and one of two 2D view types. A framebuffer
|
||||||
// whose colour attachment is RGBA8UI, or a layer of a 3D texture, is none of those, and on a
|
// whose color attachment is RGBA8UI, or a layer of a 3D texture, is none of those, and on a
|
||||||
// rotated Android surface there is no other arm - an axis-aligned vkCmdBlitImage cannot
|
// rotated Android surface there is no other arm - an axis-aligned vkCmdBlitImage cannot
|
||||||
// express a quarter turn. So the source region becomes an owned 2D image first, through
|
// express a quarter turn. So the source region becomes an owned 2D image first, through
|
||||||
// vkCmdCopyImage, which cares about the texel BLOCK SIZE and not about how the block is
|
// vkCmdCopyImage, which cares about the texel BLOCK SIZE and not about how the block is
|
||||||
@@ -163,7 +163,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
static_cast<Uint64>(std::max(sx0, sx1)) > source.extent.width ||
|
static_cast<Uint64>(std::max(sx0, sx1)) > source.extent.width ||
|
||||||
static_cast<Uint64>(std::max(sy0, sy1)) > source.extent.height)
|
static_cast<Uint64>(std::max(sy0, sy1)) > source.extent.height)
|
||||||
return false;
|
return false;
|
||||||
// A compressed source cannot be a colour attachment, so it cannot be a framebuffer blit's
|
// A compressed source cannot be a color attachment, so it cannot be a framebuffer blit's
|
||||||
// source either - but the block arithmetic below would silently produce nonsense for one,
|
// source either - but the block arithmetic below would silently produce nonsense for one,
|
||||||
// and "cannot happen" is the reason the guards this package retires were written as
|
// and "cannot happen" is the reason the guards this package retires were written as
|
||||||
// asserts. The size-compatibility classes are Vulkan's own (VkFormat texel block size);
|
// asserts. The size-compatibility classes are Vulkan's own (VkFormat texel block size);
|
||||||
|
|||||||
@@ -10,28 +10,28 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
#include "../VkIncludes.h"
|
#include "../VkIncludes.h"
|
||||||
|
|
||||||
// P7 g3-blit (g3det, gate 3): WHICH SAMPLER THE WIRE ARM'S SHADER COLOUR BLIT READS ITS SOURCE
|
// P7 g3-blit (g3det, gate 3): WHICH SAMPLER THE WIRE ARM'S SHADER COLOR BLIT READS ITS SOURCE
|
||||||
// THROUGH.
|
// THROUGH.
|
||||||
//
|
//
|
||||||
// GL applies a blit's `filter` only where the image is STRETCHED (GL 4.6 core 18.3.1). A blit whose
|
// GL applies a blit's `filter` only where the image is STRETCHED (GL 4.6 core 18.3.1). A blit whose
|
||||||
// source and destination rectangles are the same size is a copy, whatever `filter` says, and so is
|
// source and destination rectangles are the same size is a copy, whatever `filter` says, and so is
|
||||||
// a mirrored one. The wire arm's shader blit (WireColorBlit.cpp, BlitWireColorImage) draws a quad
|
// a mirrored one. The wire arm's shader blit (WireColorBlit.cpp, BlitWireColorImage) draws a quad
|
||||||
// and samples `textureLod(sourceImage, texCoord, 0)` at interpolated coordinates, and it used the
|
// and samples `textureLod(sourceImage, texCoord, 0)` at interpolated coordinates, and it used the
|
||||||
// LINEAR sampler for every GL_LINEAR blit. At 1:1 every fragment centre maps to a texel centre, so
|
// LINEAR sampler for every GL_LINEAR blit. At 1:1 every fragment center maps to a texel center, so
|
||||||
// in exact arithmetic linear filtering reads the same single texel. Adreno 830 quantises the
|
// in exact arithmetic linear filtering reads the same single texel. Adreno 830 quantises the
|
||||||
// coordinate to sub-texel precision: a fragment that lands a fraction off the centre blends in a
|
// coordinate to sub-texel precision: a fragment that lands a fraction off the center blends in a
|
||||||
// small weight of a neighbour. minecraft-1.21.1-neoforge-create-instancing-in-world ends with a
|
// small weight of a neighbor. minecraft-1.21.1-neoforge-create-instancing-in-world ends with a
|
||||||
// 1:1 GL_LINEAR glBlitFramebuffer into FB 0, and on the wire arm 712 high-contrast pixels moved by
|
// 1:1 GL_LINEAR glBlitFramebuffer into FB 0, and on the wire arm 712 high-contrast pixels moved by
|
||||||
// 1 LSB toward a neighbour. The monolith's vkCmdBlitImage copied them exactly
|
// 1 LSB toward a neighbor. The monolith's vkCmdBlitImage copied them exactly
|
||||||
// (~/w7/logs/g3det/VERDICT.md section 3). NEAREST within half a texel of the centre is exact, so an
|
// (~/w7/logs/g3det/VERDICT.md section 3). NEAREST within half a texel of the center is exact, so an
|
||||||
// unscaled blit takes NEAREST. Lavapipe samples texel centres exactly, so no host picture can see
|
// unscaled blit takes NEAREST. Lavapipe samples texel centers exactly, so no host picture can see
|
||||||
// the difference; this pure half is what the unit test pins
|
// the difference; this pure half is what the unit test pins
|
||||||
// (MG_Test/Pipeline/PipelineQuirkTest.cpp, WireColorBlitSamples*).
|
// (MG_Test/Pipeline/PipelineQuirkTest.cpp, WireColorBlitSamples*).
|
||||||
//
|
//
|
||||||
// THE SURFACE TRANSFORM DOES NOT TURN A COPY INTO A STRETCH. BlitWireColorImage applies the
|
// THE SURFACE TRANSFORM DOES NOT TURN A COPY INTO A STRETCH. BlitWireColorImage applies the
|
||||||
// quarter and half turns in NDC, over a viewport of the native image, and for a quarter turn it
|
// quarter and half turns in NDC, over a viewport of the native image, and for a quarter turn it
|
||||||
// takes the logical extent as the native extent swapped. A native pixel then has exactly the pitch
|
// takes the logical extent as the native extent swapped. A native pixel then has exactly the pitch
|
||||||
// of a logical one, and the rotation maps pixel centres onto pixel centres. So the scale test is on
|
// of a logical one, and the rotation maps pixel centers onto pixel centers. So the scale test is on
|
||||||
// GL's own (logical) rectangles for identity and all three rotations. BlitWireColorImage declines
|
// GL's own (logical) rectangles for identity and all three rotations. BlitWireColorImage declines
|
||||||
// any other transform before it chooses a sampler; for one, this answers with the filter's own
|
// any other transform before it chooses a sampler; for one, this answers with the filter's own
|
||||||
// mapping, as before this package.
|
// mapping, as before this package.
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
VkPhysicalDeviceMemoryProperties memoryProperties{};
|
VkPhysicalDeviceMemoryProperties memoryProperties{};
|
||||||
vkGetPhysicalDeviceMemoryProperties(context.physicalDevice, &memoryProperties);
|
vkGetPhysicalDeviceMemoryProperties(context.physicalDevice, &memoryProperties);
|
||||||
// The wire's images (VkTextureManager): MUTABLE_FORMAT (a storage-compatible colour class),
|
// The wire's images (VkTextureManager): MUTABLE_FORMAT (a storage-compatible color class),
|
||||||
// SAMPLED | TRANSFER_SRC | TRANSFER_DST | COLOR_ATTACHMENT, a 3D one 2D_ARRAY_COMPATIBLE.
|
// SAMPLED | TRANSFER_SRC | TRANSFER_DST | COLOR_ATTACHMENT, a 3D one 2D_ARRAY_COMPATIBLE.
|
||||||
const auto makeImage = [&](Bool volume, VkFormat format, VkImage& out) -> Bool {
|
const auto makeImage = [&](Bool volume, VkFormat format, VkImage& out) -> Bool {
|
||||||
VkFormatProperties formatProperties{};
|
VkFormatProperties formatProperties{};
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
depthStencil.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
depthStencil.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
depthStencil.minDepthBounds = 0.0f;
|
depthStencil.minDepthBounds = 0.0f;
|
||||||
depthStencil.maxDepthBounds = 1.0f;
|
depthStencil.maxDepthBounds = 1.0f;
|
||||||
// No colour attachment in this render pass, so no attachment states either.
|
// No color attachment in this render pass, so no attachment states either.
|
||||||
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||||
const VkDynamicState dynamicStates[]{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
const VkDynamicState dynamicStates[]{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
||||||
VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
|
VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
|
||||||
@@ -269,7 +269,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
framebufferInfo.layers = 1;
|
framebufferInfo.layers = 1;
|
||||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &framebuffer));
|
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &framebuffer));
|
||||||
// Each in-flight pass owns its descriptor set, for the colour blit's reason: updating
|
// Each in-flight pass owns its descriptor set, for the color blit's reason: updating
|
||||||
// a cached set would rewrite the source view of an older queued pass.
|
// a cached set would rewrite the source view of an older queued pass.
|
||||||
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
||||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (result != VK_SUCCESS) return result;
|
if (result != VK_SUCCESS) return result;
|
||||||
// THE STENCIL MODULE IS ONLY CREATED WHERE IT CAN RUN: its SPIR-V declares the
|
// THE STENCIL MODULE IS ONLY CREATED WHERE IT CAN RUN: its SPIR-V declares the
|
||||||
// StencilExportEXT capability, and handing a module with an unsupported capability to
|
// StencilExportEXT capability, and handing a module with an unsupported capability to
|
||||||
// vkCreateShaderModule is undefined behaviour - not an error this could catch.
|
// vkCreateShaderModule is undefined behavior - not an error this could catch.
|
||||||
if (shaderStencilExport) {
|
if (shaderStencilExport) {
|
||||||
result = shader(kWireMultisampleStencilResolveFragmentSpirv,
|
result = shader(kWireMultisampleStencilResolveFragmentSpirv,
|
||||||
sizeof(kWireMultisampleStencilResolveFragmentSpirv), kit.stencilFragment);
|
sizeof(kWireMultisampleStencilResolveFragmentSpirv), kit.stencilFragment);
|
||||||
@@ -206,7 +206,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
op.reference = 0;
|
op.reference = 0;
|
||||||
depthStencilState.front = depthStencilState.back = op;
|
depthStencilState.front = depthStencilState.back = op;
|
||||||
}
|
}
|
||||||
// No colour attachment in this render pass, so no attachment states either.
|
// No color attachment in this render pass, so no attachment states either.
|
||||||
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
||||||
const VkDynamicState dynamicStates[]{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
const VkDynamicState dynamicStates[]{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
||||||
VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
|
VkPipelineDynamicStateCreateInfo dynamic{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
|
||||||
|
|||||||
@@ -1175,7 +1175,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Every write goes through the pass's attachment views (the UNORM twin of an sRGB image while
|
// Every write goes through the pass's attachment views (the UNORM twin of an sRGB image while
|
||||||
// GL_FRAMEBUFFER_SRGB is off, exactly GL's raw clear - no pre-compensation), and wire attachments
|
// GL_FRAMEBUFFER_SRGB is off, exactly GL's raw clear - no pre-compensation), and wire attachments
|
||||||
// live in GENERAL. What none of this expresses goes back to the standalone path, per GL buffer
|
// live in GENERAL. What none of this expresses goes back to the standalone path, per GL buffer
|
||||||
// bit: a partial colour or stencil write mask (that path warns and skips, as before), an
|
// bit: a partial color or stencil write mask (that path warns and skips, as before), an
|
||||||
// attachment whose extent or layer count differs from the pass's (the pass covers the common area
|
// attachment whose extent or layer count differs from the pass's (the pass covers the common area
|
||||||
// only), and a stencil clear the pass's depth attachment does not carry.
|
// only), and a stencil clear the pass's depth attachment does not carry.
|
||||||
GLbitfield VulkanRenderer::ClearWireFramebufferInPass(const MG_Pipe::MGPFramebufferState& fbo,
|
GLbitfield VulkanRenderer::ClearWireFramebufferInPass(const MG_Pipe::MGPFramebufferState& fbo,
|
||||||
@@ -1185,7 +1185,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Nested inside a draw's preparation the scratch and the pass belong to that draw.
|
// Nested inside a draw's preparation the scratch and the pass belong to that draw.
|
||||||
if (m_wirePreparationDepth != 0) return remaining;
|
if (m_wirePreparationDepth != 0) return remaining;
|
||||||
// NOT THE DEFAULT FRAMEBUFFER (measured, not understood): on Adreno 750 the openra retrace
|
// NOT THE DEFAULT FRAMEBUFFER (measured, not understood): on Adreno 750 the openra retrace
|
||||||
// loses its palette-sampled sprites (SSIM 0.956) when a colour+depth clear of the default
|
// loses its palette-sampled sprites (SSIM 0.956) when a color+depth clear of the default
|
||||||
// framebuffer becomes part of its draw pass - with LOAD_OP_CLEAR as well as with
|
// framebuffer becomes part of its draw pass - with LOAD_OP_CLEAR as well as with
|
||||||
// vkCmdClearAttachments - while the same clear split across the two paths, or left
|
// vkCmdClearAttachments - while the same clear split across the two paths, or left
|
||||||
// standalone, renders correctly. Default-framebuffer clears keep the standalone path until
|
// standalone, renders correctly. Default-framebuffer clears keep the standalone path until
|
||||||
@@ -1354,7 +1354,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The draw pass `begun` with LOAD_OP_CLEAR for the attachments `variantKey` names (bit 2a:
|
// The draw pass `begun` with LOAD_OP_CLEAR for the attachments `variantKey` names (bit 2a:
|
||||||
// attachment a's colour or depth, bit 2a+1: its stencil). Built once per key and kept on the
|
// attachment a's color or depth, bit 2a+1: its stencil). Built once per key and kept on the
|
||||||
// pass, like the pass itself.
|
// pass, like the pass itself.
|
||||||
VkRenderPass VulkanRenderer::WireClearVariant(RenderPassEntry& begun, Uint64 variantKey) {
|
VkRenderPass VulkanRenderer::WireClearVariant(RenderPassEntry& begun, Uint64 variantKey) {
|
||||||
for (const auto& entry : begun.clearVariants)
|
for (const auto& entry : begun.clearVariants)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
// level return every non-canonical word canonicalized, while a 16x16 or 64x64 level reads back verbatim.
|
// level return every non-canonical word canonicalized, while a 16x16 or 64x64 level reads back verbatim.
|
||||||
// The stored words are intact - a shader reading the same image through an R32_UINT view sees
|
// The stored words are intact - a shader reading the same image through an R32_UINT view sees
|
||||||
// every one of them - and so are transfer WRITES into it. Measured with format lists, without
|
// every one of them - and so are transfer WRITES into it. Measured with format lists, without
|
||||||
// the colour-attachment usage and with storage usage: none of them changes the answer, and the
|
// the color-attachment usage and with storage usage: none of them changes the answer, and the
|
||||||
// device has no VK_EXT_image_compression_control to ask with.
|
// device has no VK_EXT_image_compression_control to ask with.
|
||||||
//
|
//
|
||||||
// The route therefore reads through a shader: a compute pass fetches the source through an
|
// The route therefore reads through a shader: a compute pass fetches the source through an
|
||||||
@@ -109,7 +109,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// comparison or the route itself is what failed, and nothing is concluded.
|
// comparison or the route itself is what failed, and nothing is concluded.
|
||||||
Uint32 controlMismatches = 0;
|
Uint32 controlMismatches = 0;
|
||||||
// Reported, not judged: the same words in a 16x16 level read back by plain transfer. Clean
|
// Reported, not judged: the same words in a 16x16 level read back by plain transfer. Clean
|
||||||
// on the device this was characterised on (power-of-two extents read back verbatim, 28, 30
|
// on the device this was characterized on (power-of-two extents read back verbatim, 28, 30
|
||||||
// and 31 do not), which is why the subject is 30x30.
|
// and 31 do not), which is why the subject is 30x30.
|
||||||
Uint32 smallTexels = 0;
|
Uint32 smallTexels = 0;
|
||||||
Uint32 smallMismatches = 0;
|
Uint32 smallMismatches = 0;
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// THE HOST GATE CANNOT REACH THE SHADER MIP ARM ON ITS OWN. lavapipe reports
|
// THE HOST GATE CANNOT REACH THE SHADER MIP ARM ON ITS OWN. lavapipe reports
|
||||||
// BLIT_SRC|BLIT_DST for every colour format this lane can create, so `nativeBlit` is
|
// BLIT_SRC|BLIT_DST for every color format this lane can create, so `nativeBlit` is
|
||||||
// always true there and both shader shapes below would only ever run on the phone -
|
// always true there and both shader shapes below would only ever run on the phone -
|
||||||
// which is how the Adreno refusal reached a release in the first place. The knob makes
|
// which is how the Adreno refusal reached a release in the first place. The knob makes
|
||||||
// them reachable from a host lane and is read exactly once:
|
// them reachable from a host lane and is read exactly once:
|
||||||
@@ -789,7 +789,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// ---- P15: WIRE DEFERRED CLEARS -------------------------------------------------------------
|
// ---- P15: WIRE DEFERRED CLEARS -------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Minecraft (1.21.5) clears its targets through framebuffers of their own - a depth-only one
|
// Minecraft (1.21.5) clears its targets through framebuffers of their own - a depth-only one
|
||||||
// for the shared depth texture, a colour+depth one per target - and then draws through the
|
// for the shared depth texture, a color+depth one per target - and then draws through the
|
||||||
// main framebuffer. A clear that begins a LOAD_OP_CLEAR pass of its own made every such clear a
|
// main framebuffer. A clear that begins a LOAD_OP_CLEAR pass of its own made every such clear a
|
||||||
// pass that did nothing but clear, closed by the very next draw: 11.5 passes a frame against
|
// pass that did nothing but clear, closed by the very next draw: 11.5 passes a frame against
|
||||||
// dev's 4.1 (whose clear manager folded the same clears into the next pass's load op), each
|
// dev's 4.1 (whose clear manager folded the same clears into the next pass's load op), each
|
||||||
@@ -805,7 +805,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// ClearWireFramebufferInPass), and it is presented, not sampled.
|
// ClearWireFramebufferInPass), and it is presented, not sampled.
|
||||||
|
|
||||||
// Whether `image` can carry a deferred clear: a plain single-sample 2D(-array) image of this
|
// Whether `image` can carry a deferred clear: a plain single-sample 2D(-array) image of this
|
||||||
// session with a float colour or a depth/stencil format, clearable by a transfer command.
|
// session with a float color or a depth/stencil format, clearable by a transfer command.
|
||||||
Bool VulkanRenderer::WireImageCanDeferClear(const WireImage& image) {
|
Bool VulkanRenderer::WireImageCanDeferClear(const WireImage& image) {
|
||||||
const auto* resource = image.resource;
|
const auto* resource = image.resource;
|
||||||
if (resource == nullptr || image.isDefault || image.is3D || image.samples != VK_SAMPLE_COUNT_1_BIT)
|
if (resource == nullptr || image.isDefault || image.is3D || image.samples != VK_SAMPLE_COUNT_1_BIT)
|
||||||
@@ -1328,7 +1328,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
!m_swapchainObject.IsImageContentDefined(source.swapchainImageIndex)) {
|
!m_swapchainObject.IsImageContentDefined(source.swapchainImageIndex)) {
|
||||||
// Named rather than silent: the readback hands back whatever the image holds. The
|
// Named rather than silent: the readback hands back whatever the image holds. The
|
||||||
// ordinary cause is a readback of the default framebuffer applied after the Present
|
// ordinary cause is a readback of the default framebuffer applied after the Present
|
||||||
// that consumed it, where the app's own colour is still what is expected (see
|
// that consumed it, where the app's own color is still what is expected (see
|
||||||
// m_defaultFramebufferImageIndex).
|
// m_defaultFramebufferImageIndex).
|
||||||
MGLOG_W_ONCE("DirectVulkan::ReadPixels: no write is recorded for swapchain image %u of the "
|
MGLOG_W_ONCE("DirectVulkan::ReadPixels: no write is recorded for swapchain image %u of the "
|
||||||
"default framebuffer; the readback returns its raw pixels",
|
"default framebuffer; the readback returns its raw pixels",
|
||||||
@@ -1416,7 +1416,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Int64 dstHeight = dstSpanY < 0 ? -dstSpanY : dstSpanY;
|
const Int64 dstHeight = dstSpanY < 0 ? -dstSpanY : dstSpanY;
|
||||||
// A SCALE has no arm here and is not supposed to: 18.3.1 makes a multisample blit whose
|
// A SCALE has no arm here and is not supposed to: 18.3.1 makes a multisample blit whose
|
||||||
// rectangles differ in size INVALID_OPERATION. Rule I (a), the same three lines the
|
// rectangles differ in size INVALID_OPERATION. Rule I (a), the same three lines the
|
||||||
// colour arm's multisample-destination decline uses. A ZERO span on one side only is a
|
// color arm's multisample-destination decline uses. A ZERO span on one side only is a
|
||||||
// size mismatch too (review round 2): it used to return silently with the other side
|
// size mismatch too (review round 2): it used to return silently with the other side
|
||||||
// non-empty, where GL raises the error. Only when BOTH sides are empty on an axis is
|
// non-empty, where GL raises the error. Only when BOTH sides are empty on an axis is
|
||||||
// there nothing to do and nothing to say - that is the caller's early return.
|
// there nothing to do and nothing to say - that is the caller's early return.
|
||||||
@@ -1602,7 +1602,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// P7 wave 2-B2 (review round): A REVERSED RECTANGLE IS NOT A MALFORMED ONE. This guard
|
// P7 wave 2-B2 (review round): A REVERSED RECTANGLE IS NOT A MALFORMED ONE. This guard
|
||||||
// used to require `sx1 > sx0` and `sy1 > sy0` and take the session with a named Fatal
|
// used to require `sx1 > sx0` and `sy1 > sy0` and take the session with a named Fatal
|
||||||
// otherwise - so `glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, COLOR|DEPTH)` out of a
|
// otherwise - so `glBlitFramebuffer(0, h, w, 0, 0, 0, w, h, COLOR|DEPTH)` out of a
|
||||||
// multisample framebuffer blitted its COLOUR correctly (the colour arm has handled a
|
// multisample framebuffer blitted its COLOR correctly (the color arm has handled a
|
||||||
// flip since P5f and now handles a scale too) and then died on its DEPTH. GL 4.6 core
|
// flip since P5f and now handles a scale too) and then died on its DEPTH. GL 4.6 core
|
||||||
// 18.3.1 asks for identical DIMENSIONS, not identical corners - a conforming check compares absolute
|
// 18.3.1 asks for identical DIMENSIONS, not identical corners - a conforming check compares absolute
|
||||||
// spans - so a flip is a legal blit that has to produce a mirrored picture.
|
// spans - so a flip is a legal blit that has to produce a mirrored picture.
|
||||||
@@ -1610,10 +1610,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// Spans are therefore signed and everything downstream works off the min corner.
|
// Spans are therefore signed and everything downstream works off the min corner.
|
||||||
//
|
//
|
||||||
// THE SHAPE DECLINES ARE DECIDED ONCE PER CALL (review round 2). BlitWireFramebuffers
|
// THE SHAPE DECLINES ARE DECIDED ONCE PER CALL (review round 2). BlitWireFramebuffers
|
||||||
// asks DeclineWireDepthStencilResolveShape before ANY aspect runs, because the colour
|
// asks DeclineWireDepthStencilResolveShape before ANY aspect runs, because the color
|
||||||
// lambda runs first: asked only here, a scaled COLOR|DEPTH blit scaled and wrote its
|
// lambda runs first: asked only here, a scaled COLOR|DEPTH blit scaled and wrote its
|
||||||
// colour and THEN recorded INVALID_OPERATION on its depth - a partial effect GL 18.3.1
|
// color and THEN recorded INVALID_OPERATION on its depth - a partial effect GL 18.3.1
|
||||||
// forbids (the whole call errors) - and an X-mirrored one mirrored its colour and left
|
// forbids (the whole call errors) - and an X-mirrored one mirrored its color and left
|
||||||
// its depth alone. The call below is the same question for a caller that did not ask;
|
// its depth alone. The call below is the same question for a caller that did not ask;
|
||||||
// on the BlitWireFramebuffers path it has already answered false.
|
// on the BlitWireFramebuffers path it has already answered false.
|
||||||
if (DeclineWireDepthStencilResolveShape(source, destination, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1)) return;
|
if (DeclineWireDepthStencilResolveShape(source, destination, sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1)) return;
|
||||||
@@ -1874,8 +1874,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (!read || !draw) MagmaWireFatal("blit-framebuffer-record");
|
if (!read || !draw) MagmaWireFatal("blit-framebuffer-record");
|
||||||
state.VerbBlitNamedConsumed = named;
|
state.VerbBlitNamedConsumed = named;
|
||||||
// P7 wave 2-B2 (review round 2): ONE ANSWER FOR THE WHOLE CALL. The aspects below run
|
// P7 wave 2-B2 (review round 2): ONE ANSWER FOR THE WHOLE CALL. The aspects below run
|
||||||
// colour first, so a multisample depth/stencil shape that declines (a scale, an X
|
// color first, so a multisample depth/stencil shape that declines (a scale, an X
|
||||||
// mirror, a Y mirror across two formats) used to be discovered only after the colour
|
// mirror, a Y mirror across two formats) used to be discovered only after the color
|
||||||
// attachment had already been scaled or mirrored and written - the call then recorded
|
// attachment had already been scaled or mirrored and written - the call then recorded
|
||||||
// INVALID_OPERATION with half its effect in place, which GL 18.3.1 does not allow (an
|
// INVALID_OPERATION with half its effect in place, which GL 18.3.1 does not allow (an
|
||||||
// erroring blit writes nothing). The shape is a fact about the rectangles and the two
|
// erroring blit writes nothing). The shape is a fact about the rectangles and the two
|
||||||
@@ -1887,7 +1887,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// on the belief that a default draw behind a multisample read was ResolveWireDepthStencil's
|
// on the belief that a default draw behind a multisample read was ResolveWireDepthStencil's
|
||||||
// region Fatal whatever the shape, but that arm asks DeclineWireDepthStencilResolveShape
|
// region Fatal whatever the shape, but that arm asks DeclineWireDepthStencilResolveShape
|
||||||
// BEFORE its region check - so a scaled (or X-mirrored) COLOR|DEPTH blit out of a
|
// BEFORE its region check - so a scaled (or X-mirrored) COLOR|DEPTH blit out of a
|
||||||
// multisample framebuffer onto the window scaled and wrote its colour through
|
// multisample framebuffer onto the window scaled and wrote its color through
|
||||||
// BlitWireColorToDefault and then recorded INVALID_OPERATION on its depth, the very
|
// BlitWireColorToDefault and then recorded INVALID_OPERATION on its depth, the very
|
||||||
// partial effect this block exists to close. Both sides are resolved as READS
|
// partial effect this block exists to close. Both sides are resolved as READS
|
||||||
// (isWriteTarget=false): only their format and samples are consulted here, and a write
|
// (isWriteTarget=false): only their format and samples are consulted here, and a write
|
||||||
@@ -2005,7 +2005,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// The filter only started MATTERING with the scale above: at 1:1 LINEAR and
|
// The filter only started MATTERING with the scale above: at 1:1 LINEAR and
|
||||||
// NEAREST read the same texel, so nothing here ever asked whether the format
|
// NEAREST read the same texel, so nothing here ever asked whether the format
|
||||||
// could be filtered. VK_FILTER_LINEAR on a source whose optimalTilingFeatures
|
// could be filtered. VK_FILTER_LINEAR on a source whose optimalTilingFeatures
|
||||||
// lack SAMPLED_IMAGE_FILTER_LINEAR is undefined behaviour, and GL says filter
|
// lack SAMPLED_IMAGE_FILTER_LINEAR is undefined behavior, and GL says filter
|
||||||
// is ignored for a multisample resolve in the first place - so a format that
|
// is ignored for a multisample resolve in the first place - so a format that
|
||||||
// cannot be filtered takes NEAREST rather than the command being illegal.
|
// cannot be filtered takes NEAREST rather than the command being illegal.
|
||||||
VkFormatProperties scratchProperties{};
|
VkFormatProperties scratchProperties{};
|
||||||
@@ -2077,7 +2077,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// express a quarter turn. It is still TAKEN FIRST on every transform it can
|
// express a quarter turn. It is still TAKEN FIRST on every transform it can
|
||||||
// express, identity included. That has been the routing since 38919d453: every
|
// express, identity included. That has been the routing since 38919d453: every
|
||||||
// host lane (all identity) and the Redmi pbuffer run their default-framebuffer
|
// host lane (all identity) and the Redmi pbuffer run their default-framebuffer
|
||||||
// colour blits through it, F1WireScenario.ColorBlitToDefaultHonorsScissorAndReversedRect
|
// color blits through it, F1WireScenario.ColorBlitToDefaultHonorsScissorAndReversedRect
|
||||||
// among them. The ordinary vkCmdBlitImage arm below is reached on identity only
|
// among them. The ordinary vkCmdBlitImage arm below is reached on identity only
|
||||||
// when this pass declines the source. Because identity blits run here, the pass
|
// when this pass declines the source. Because identity blits run here, the pass
|
||||||
// must copy exactly wherever GL says the blit is a copy: an unscaled blit samples
|
// must copy exactly wherever GL says the blit is a copy: an unscaled blit samples
|
||||||
@@ -2179,7 +2179,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// P7 wave 2-B2, CONTRACT-P7 §3.2: WHAT IS LEFT HERE IS A MULTISAMPLE DESTINATION.
|
// P7 wave 2-B2, CONTRACT-P7 §3.2: WHAT IS LEFT HERE IS A MULTISAMPLE DESTINATION.
|
||||||
// Every blit that resolves a multisample SOURCE into a single-sample destination
|
// Every blit that resolves a multisample SOURCE into a single-sample destination
|
||||||
// returned above - the depth/stencil arm at the top of this lambda through
|
// returned above - the depth/stencil arm at the top of this lambda through
|
||||||
// ResolveWireDepthStencil, the colour arm below it through its resolve scratch -
|
// ResolveWireDepthStencil, the color arm below it through its resolve scratch -
|
||||||
// and both of those now carry their own scale and flip. So the samples of the two
|
// and both of those now carry their own scale and flip. So the samples of the two
|
||||||
// sides can only differ here by the DESTINATION being multisampled, which is the
|
// sides can only differ here by the DESTINATION being multisampled, which is the
|
||||||
// shape this arm declines rather than the one it performs.
|
// shape this arm declines rather than the one it performs.
|
||||||
@@ -2423,7 +2423,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
const Bool depthArmTakesShape =
|
const Bool depthArmTakesShape =
|
||||||
planar && layersInRange && (props.optimalTilingFeatures & depthPassFeatures) == depthPassFeatures;
|
planar && layersInRange && (props.optimalTilingFeatures & depthPassFeatures) == depthPassFeatures;
|
||||||
// The colour arm's shape (the two shader shapes are explained at the colour arm below).
|
// The color arm's shape (the two shader shapes are explained at the color arm below).
|
||||||
const Bool colour = resource->aspect == VK_IMAGE_ASPECT_COLOR_BIT;
|
const Bool colour = resource->aspect == VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
// The shader arm samples through a sampler2D and writes a vec4, which is what
|
// The shader arm samples through a sampler2D and writes a vec4, which is what
|
||||||
// BlitWireColorImage's own float check enforces; naming it here rather than letting the
|
// BlitWireColorImage's own float check enforces; naming it here rather than letting the
|
||||||
@@ -2459,7 +2459,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// P7 wave 2-B, CONTRACT-P7 §5.1 (A): THE DEPTH ARM, and it is first because a
|
// P7 wave 2-B, CONTRACT-P7 §5.1 (A): THE DEPTH ARM, and it is first because a
|
||||||
// depth format without BLIT_DST is the ordinary case, not the exotic one -
|
// depth format without BLIT_DST is the ordinary case, not the exotic one -
|
||||||
// VK_FORMAT_FEATURE_BLIT_DST is optional for depth and plenty of devices decline
|
// VK_FORMAT_FEATURE_BLIT_DST is optional for depth and plenty of devices decline
|
||||||
// it. Before this package the whole branch below was colour-only, so such a
|
// it. Before this package the whole branch below was color-only, so such a
|
||||||
// texture reached `mipmap-shader-format-or-shape` on its very first disjunction
|
// texture reached `mipmap-shader-format-or-shape` on its very first disjunction
|
||||||
// while the monolith arm quietly generated the chain with a shader.
|
// while the monolith arm quietly generated the chain with a shader.
|
||||||
//
|
//
|
||||||
@@ -2511,7 +2511,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// TWO SHADER SHAPES, not one. The arm that was here rendered STRAIGHT INTO the
|
// TWO SHADER SHAPES, not one. The arm that was here rendered STRAIGHT INTO the
|
||||||
// next level, which needs the image to have been created with
|
// next level, which needs the image to have been created with
|
||||||
// COLOR_ATTACHMENT usage - and a texture whose format the device refuses as a
|
// COLOR_ATTACHMENT usage - and a texture whose format the device refuses as a
|
||||||
// colour attachment never gets that bit (VkTextureManager.cpp:2156-2160), so
|
// color attachment never gets that bit (VkTextureManager.cpp:2156-2160), so
|
||||||
// every sampled-only texture without BLIT support fell into the refusal rather
|
// every sampled-only texture without BLIT support fell into the refusal rather
|
||||||
// than into a fallback. When the FORMAT can be rendered and only the IMAGE
|
// than into a fallback. When the FORMAT can be rendered and only the IMAGE
|
||||||
// cannot, an owned scratch attachment of the destination level's size renders
|
// cannot, an owned scratch attachment of the destination level's size renders
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// GL shader compiler. It is WireDepthMipmap.cpp's pass with the box filter taken out and a
|
// GL shader compiler. It is WireDepthMipmap.cpp's pass with the box filter taken out and a
|
||||||
// sample index put in.
|
// sample index put in.
|
||||||
//
|
//
|
||||||
// WHY THIS FILE EXISTS. vkCmdResolveImage is COLOUR ONLY. The one way Vulkan resolves a depth
|
// WHY THIS FILE EXISTS. vkCmdResolveImage is COLOR ONLY. The one way Vulkan resolves a depth
|
||||||
// or stencil aspect without a shader is a render pass with a depth/stencil resolve attachment,
|
// or stencil aspect without a shader is a render pass with a depth/stencil resolve attachment,
|
||||||
// which needs VK_KHR_create_renderpass2 and VK_KHR_depth_stencil_resolve - and until this
|
// which needs VK_KHR_create_renderpass2 and VK_KHR_depth_stencil_resolve - and until this
|
||||||
// package a device without either killed the session at
|
// package a device without either killed the session at
|
||||||
@@ -138,7 +138,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &framebuffer));
|
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &framebuffer));
|
||||||
|
|
||||||
// Each in-flight pass owns its descriptor set, for the colour blit's reason: updating a
|
// Each in-flight pass owns its descriptor set, for the color blit's reason: updating a
|
||||||
// cached set would rewrite the source view of an older queued pass.
|
// cached set would rewrite the source view of an older queued pass.
|
||||||
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
||||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
// Every private placeholder is its own vkCreateImage + vkAllocateMemory, freed only at Shutdown.
|
// Every private placeholder is its own vkCreateImage + vkAllocateMemory, freed only at Shutdown.
|
||||||
// (shape, unit) bounds them by shapes x kMGPipeMaxImageUnits, and a peer rotating formats and
|
// (shape, unit) bounds them by shapes x kMGPipeMaxImageUnits, and a peer rotating formats and
|
||||||
// targets across the units could still walk that towards maxMemoryAllocationCount (4096 is the
|
// targets across the units could still walk that toward maxMemoryAllocationCount (4096 is the
|
||||||
// spec minimum). So past this many, a NEW (shape, unit) takes its shape's SHARED placeholder - the
|
// spec minimum). So past this many, a NEW (shape, unit) takes its shape's SHARED placeholder - the
|
||||||
// pre-fix aliasing, logged once by the caller - instead of another allocation; a unit that already
|
// pre-fix aliasing, logged once by the caller - instead of another allocation; a unit that already
|
||||||
// has its private placeholder keeps it. Two per unit is far past any real program.
|
// has its private placeholder keeps it. Two per unit is far past any real program.
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// texture's image: the texture keeps its own RGBA8 level 0 (VkTextureManager::SyncWireTextureShape)
|
// texture's image: the texture keeps its own RGBA8 level 0 (VkTextureManager::SyncWireTextureShape)
|
||||||
// and, at its first use in each frame, the image is CONVERTED into it here - the image's
|
// and, at its first use in each frame, the image is CONVERTED into it here - the image's
|
||||||
// AHardwareBuffer imported with its external format, sampled through an immutable sampler that
|
// AHardwareBuffer imported with its external format, sampled through an immutable sampler that
|
||||||
// carries a VkSamplerYcbcrConversion built from the import's colour hints, one triangle over the
|
// carries a VkSamplerYcbcrConversion built from the import's color hints, one triangle over the
|
||||||
// target. Zero CPU copies for an image this server allocated; a foreign one (a video decoder's
|
// target. Zero CPU copies for an image this server allocated; a foreign one (a video decoder's
|
||||||
// buffer) is first brought up to date by the registry's labelled CPU copy (RefreshForeign).
|
// buffer) is first brought up to date by the registry's labeled CPU copy (RefreshForeign).
|
||||||
//
|
//
|
||||||
// Why converted rather than sampled in place: a Y'CbCr conversion is an immutable sampler, which
|
// Why converted rather than sampled in place: a Y'CbCr conversion is an immutable sampler, which
|
||||||
// lives in the descriptor set layout and therefore in every application pipeline that samples the
|
// lives in the descriptor set layout and therefore in every application pipeline that samples the
|
||||||
@@ -154,7 +154,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
// ---- the texture's import of the buffer, and the pipeline its conversion needs ----
|
// ---- the texture's import of the buffer, and the pipeline its conversion needs ----
|
||||||
auto* source = static_cast<WireYuvSource*>(resource.yuvSource.get());
|
auto* source = static_cast<WireYuvSource*>(resource.yuvSource.get());
|
||||||
if (source != nullptr && !(source->hints == hints)) {
|
if (source != nullptr && !(source->hints == hints)) {
|
||||||
// Re-imported with other colour hints: the conversion (and so the view) changes.
|
// Re-imported with other color hints: the conversion (and so the view) changes.
|
||||||
auto retired = MakeUnique<VkTextureManager::TextureResource>();
|
auto retired = MakeUnique<VkTextureManager::TextureResource>();
|
||||||
retired->yuvSource = std::move(resource.yuvSource);
|
retired->yuvSource = std::move(resource.yuvSource);
|
||||||
WireRetiredObjects objects{};
|
WireRetiredObjects objects{};
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
// a bit derived from `ActiveBackendType == ...` would keep claiming the capability
|
// a bit derived from `ActiveBackendType == ...` would keep claiming the capability
|
||||||
// for a build, a flavour or a future backend whose table does not carry the arm -
|
// for a build, a flavour or a future backend whose table does not carry the arm -
|
||||||
// which is exactly how 66 uploads were lost to a consumer bit that nobody could
|
// which is exactly how 66 uploads were lost to a consumer bit that nobody could
|
||||||
// have honoured. `g_resourceOpsAtStep2` is the pointer this function just pinned,
|
// have honored. `g_resourceOpsAtStep2` is the pointer this function just pinned,
|
||||||
// and step 5 already refuses a run where that pointer was swapped underneath us, so
|
// and step 5 already refuses a run where that pointer was swapped underneath us, so
|
||||||
// reading the arm off it means the published bit and the table that has to answer
|
// reading the arm off it means the published bit and the table that has to answer
|
||||||
// for it cannot come apart.
|
// for it cannot come apart.
|
||||||
|
|||||||
@@ -353,11 +353,11 @@ namespace MobileGL::MG_Pipe {
|
|||||||
|
|
||||||
void MGPipeServerBlockNoteIdentity() {
|
void MGPipeServerBlockNoteIdentity() {
|
||||||
// D10: THE WIDER PREDICATE, and the narrow one was a latent crash rather than a missing
|
// D10: THE WIDER PREDICATE, and the narrow one was a latent crash rather than a missing
|
||||||
// optimisation. Gated on the REHEARSAL, this early-returned for the whole life of a
|
// optimization. Gated on the REHEARSAL, this early-returned for the whole life of a
|
||||||
// spawn server - because that knob is off by default and nothing in the spawn shape
|
// spawn server - because that knob is off by default and nothing in the spawn shape
|
||||||
// turns it on - so the server's gPipeInputs->ContextIdentity() stayed nullptr forever.
|
// turns it on - so the server's gPipeInputs->ContextIdentity() stayed nullptr forever.
|
||||||
// DirectGLES' fb-slot memo compares that identity FIRST and with no generation, so a
|
// DirectGLES' fb-slot memo compares that identity FIRST and with no generation, so a
|
||||||
// nullptr against its own nullptr initialiser reads as a CACHE HIT and hands out a slot
|
// nullptr against its own nullptr initializer reads as a CACHE HIT and hands out a slot
|
||||||
// that was never filled. `st` lands the named Fatal at that site; this is the gate that
|
// that was never filled. `st` lands the named Fatal at that site; this is the gate that
|
||||||
// stops it being reachable in the first place.
|
// stops it being reachable in the first place.
|
||||||
if (!MGPipeBlocksAreDistinct()) return;
|
if (!MGPipeBlocksAreDistinct()) return;
|
||||||
@@ -366,7 +366,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// served-context clock: MGPipeApplierContextSerial moves exactly when the served
|
// served-context clock: MGPipeApplierContextSerial moves exactly when the served
|
||||||
// context does (MGPipeApplierReset), which is all the backends' per-context memo keys
|
// context does (MGPipeApplierReset), which is all the backends' per-context memo keys
|
||||||
// ask of an identity. The odd-encoding keeps the token non-null at serial 0: a null
|
// ask of an identity. The odd-encoding keeps the token non-null at serial 0: a null
|
||||||
// identity reads as a hit against DirectGLES' zero-initialised fb-slot memo cache and
|
// identity reads as a hit against DirectGLES' zero-initialized fb-slot memo cache and
|
||||||
// hands out a null slot - an unnamed crash where the rehearsal exists to produce a
|
// hands out a null slot - an unnamed crash where the rehearsal exists to produce a
|
||||||
// named one.
|
// named one.
|
||||||
const Uint64 serial = MGPipeApplierContextSerial();
|
const Uint64 serial = MGPipeApplierContextSerial();
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// such a verb is a BARRIER_PULLED read counted rather than Fatal, and only there is a
|
// such a verb is a BARRIER_PULLED read counted rather than Fatal, and only there is a
|
||||||
// sticky forward a residual pull. PipeApplier::LeaveApplier must clear it after every
|
// sticky forward a residual pull. PipeApplier::LeaveApplier must clear it after every
|
||||||
// record: a server process has no client half to do it, so the flag would stay set and
|
// record: a server process has no client half to do it, so the flag would stay set and
|
||||||
// later reads (InvalidateCompileEnv during another context's backend initialisation)
|
// later reads (InvalidateCompileEnv during another context's backend initialization)
|
||||||
// would be judged against the last verb's mask.
|
// would be judged against the last verb's mask.
|
||||||
Bool ServerStampedVerb() const { return m_serverStampedVerb; }
|
Bool ServerStampedVerb() const { return m_serverStampedVerb; }
|
||||||
|
|
||||||
@@ -622,7 +622,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// them with handle tables and callbacks.
|
// them with handle tables and callbacks.
|
||||||
// They carry no MGP_INPUT_CHECK / MGP_INPUT_VERIFY_READ (the declared exception to
|
// They carry no MGP_INPUT_CHECK / MGP_INPUT_VERIFY_READ (the declared exception to
|
||||||
// P1 brief D4's "every accessor body"): a forward is a live call, not a stored value,
|
// P1 brief D4's "every accessor body"): a forward is a live call, not a stored value,
|
||||||
// and InvalidateCompileEnv is reached from backend initialisation before any verb has
|
// and InvalidateCompileEnv is reached from backend initialization before any verb has
|
||||||
// filled, where a check would be Fatal{...@<none>} on every start. Their sticky stamp
|
// filled, where a check would be Fatal{...@<none>} on every start. Their sticky stamp
|
||||||
// is therefore consulted by no accessor; the tests pin it through
|
// is therefore consulted by no accessor; the tests pin it through
|
||||||
// MGPipeInputFieldIsFresh directly.
|
// MGPipeInputFieldIsFresh directly.
|
||||||
@@ -689,7 +689,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// MGPipeServerSetContextLive's flag. In the block, not in a process global, because the
|
// MGPipeServerSetContextLive's flag. In the block, not in a process global, because the
|
||||||
// in-process display server runs several sessions at once and each has its own served
|
// in-process display server runs several sessions at once and each has its own served
|
||||||
// context: one session's teardown or eglMakeCurrent(NO_CONTEXT) must not mark a
|
// context: one session's teardown or eglMakeCurrent(NO_CONTEXT) must not mark a
|
||||||
// neighbour's context dead mid-frame (P14; the per-thread block resolution below is
|
// neighbor's context dead mid-frame (P14; the per-thread block resolution below is
|
||||||
// what makes this the calling session's).
|
// what makes this the calling session's).
|
||||||
Bool m_serverContextLive = false;
|
Bool m_serverContextLive = false;
|
||||||
MGPipeVerb m_currentVerb = MGPipeVerb::kVerbCount;
|
MGPipeVerb m_currentVerb = MGPipeVerb::kVerbCount;
|
||||||
@@ -896,7 +896,7 @@ namespace MobileGL::MG_Pipe {
|
|||||||
// from MGPipeApplierContextSerial() - the server's own served-context clock, which is what
|
// from MGPipeApplierContextSerial() - the server's own served-context clock, which is what
|
||||||
// moves when the served context does. Without it the server block's ContextIdentity() would
|
// moves when the served context does. Without it the server block's ContextIdentity() would
|
||||||
// stay nullptr, and DirectGLES' fb-slot memo cache compares identity FIRST (a nullptr
|
// stay nullptr, and DirectGLES' fb-slot memo cache compares identity FIRST (a nullptr
|
||||||
// against its own nullptr initialiser reads as a hit and hands out a null slot): an
|
// against its own nullptr initializer reads as a hit and hands out a null slot): an
|
||||||
// unnamed crash where the rehearsal exists to produce a named one. A no-op with the
|
// unnamed crash where the rehearsal exists to produce a named one. A no-op with the
|
||||||
// rehearsal off, so the client's per-verb SetIdentity keeps owning the shared block there.
|
// rehearsal off, so the client's per-verb SetIdentity keeps owning the shared block there.
|
||||||
void MGPipeServerBlockNoteIdentity();
|
void MGPipeServerBlockNoteIdentity();
|
||||||
|
|||||||
@@ -98,9 +98,9 @@ namespace MobileGL::MG_Record {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// A value class outside the three is a wire fault, not a fallback: all three
|
// A value class outside the three is a wire fault, not a fallback: all three
|
||||||
// representations of a clear colour are numerically populated by the frontend
|
// representations of a clear color are numerically populated by the frontend
|
||||||
// and only this field says which one the backend must use, so guessing renders
|
// and only this field says which one the backend must use, so guessing renders
|
||||||
// a plausible wrong colour.
|
// a plausible wrong color.
|
||||||
MG_Pipe::MGPipeProtocolFatalAt("MGPClear::ValueClass", clear.ValueClass, 3);
|
MG_Pipe::MGPipeProtocolFatalAt("MGPClear::ValueClass", clear.ValueClass, 3);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -227,7 +227,7 @@ namespace MobileGL::MG_Record {
|
|||||||
// scatters it per its own GL_PACK_* state, so a DstSize that disagrees with the tight
|
// scatters it per its own GL_PACK_* state, so a DstSize that disagrees with the tight
|
||||||
// extent (a client that sized its destination with pack padding) is logged and the tight
|
// extent (a client that sized its destination with pack padding) is logged and the tight
|
||||||
// extent this side owns is read and posted - never the client's number, so a wrong
|
// extent this side owns is read and posted - never the client's number, so a wrong
|
||||||
// DstSize cannot make this a short read into uninitialised scratch. F2's first PH-3 draft
|
// DstSize cannot make this a short read into uninitialized scratch. F2's first PH-3 draft
|
||||||
// refused the mismatch instead, which broke the ID-49 control
|
// refused the mismatch instead, which broke the ID-49 control
|
||||||
// (ServerLoopEglTest.AReadPixelsReplyIsTheTightExtentWhateverDstSizeTheClientSent); the
|
// (ServerLoopEglTest.AReadPixelsReplyIsTheTightExtentWhateverDstSizeTheClientSent); the
|
||||||
// bound above is what PH-3 needs and it does not depend on DstSize.
|
// bound above is what PH-3 needs and it does not depend on DstSize.
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
// INVALIDATE_RANGE clobbered GPU-written data - an SSBO counter beside the app's SubData - with
|
// INVALIDATE_RANGE clobbered GPU-written data - an SSBO counter beside the app's SubData - with
|
||||||
// stale shadow bytes (FlushPendingRangesFrom, ManagersBuffers.cpp). Tier 1's INVALIDATE_RANGE is an ASSERTION that
|
// stale shadow bytes (FlushPendingRangesFrom, ManagersBuffers.cpp). Tier 1's INVALIDATE_RANGE is an ASSERTION that
|
||||||
// the old bytes are dead, so declaring bytes covered that nothing staged is not a missing
|
// the old bytes are dead, so declaring bytes covered that nothing staged is not a missing
|
||||||
// optimisation, it is a silent data loss. The coverage set below is therefore exact, and a
|
// optimization, it is a silent data loss. The coverage set below is therefore exact, and a
|
||||||
// drain that reaches outside it is Fatal rather than a re-read of whatever happens to be there.
|
// drain that reaches outside it is Fatal rather than a re-read of whatever happens to be there.
|
||||||
//
|
//
|
||||||
// WHY IT IS A HEADER AND NOT A BLOCK INSIDE Managers.cpp. Two reasons, and the second is the
|
// WHY IT IS A HEADER AND NOT A BLOCK INSIDE Managers.cpp. Two reasons, and the second is the
|
||||||
@@ -55,7 +55,7 @@ namespace MobileGL::MG_Record {
|
|||||||
// P14: WHOSE STAGED BYTES ARE THESE? The two server stores below are one per process, but the
|
// P14: WHOSE STAGED BYTES ARE THESE? The two server stores below are one per process, but the
|
||||||
// in-process display server serves several sessions in that process at once, and a session's
|
// in-process display server serves several sessions in that process at once, and a session's
|
||||||
// end (DestroyEGLContext's OnBackendContextDestroyed) used to DropAll() them - every live
|
// end (DestroyEGLContext's OnBackendContextDestroyed) used to DropAll() them - every live
|
||||||
// neighbour's declared texture levels and buffer shadows with it. The neighbour's next upload
|
// neighbor's declared texture levels and buffer shadows with it. The neighbor's next upload
|
||||||
// into a texture it had declared long ago then read as "resource_subdata arrived before the
|
// into a texture it had declared long ago then read as "resource_subdata arrived before the
|
||||||
// server declared texture level", a Fatal that took the whole display process (and so every
|
// server declared texture level", a Fatal that took the whole display process (and so every
|
||||||
// session in it) down. The texture store is also keyed by the client's {slot, gen}, which two
|
// session in it) down. The texture store is also keyed by the client's {slot, gen}, which two
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
// that lets the sync read - the set is complete exactly when every piece has landed, and a level
|
// that lets the sync read - the set is complete exactly when every piece has landed, and a level
|
||||||
// with a hole in it is Fatal{StageSnapshotTooNarrow}: the same words as the buffer half, for the
|
// with a hole in it is Fatal{StageSnapshotTooNarrow}: the same words as the buffer half, for the
|
||||||
// same reason, because those bytes have never existed on this side and inventing them is silent
|
// same reason, because those bytes have never existed on this side and inventing them is silent
|
||||||
// data loss rather than a missing optimisation. THE QUESTION IS "IS THE RANGE THE READER ASKS
|
// data loss rather than a missing optimization. THE QUESTION IS "IS THE RANGE THE READER ASKS
|
||||||
// FOR COVERED", not "is the level the size the client meant": no format crosses the wire, so a
|
// FOR COVERED", not "is the level the size the client meant": no format crosses the wire, so a
|
||||||
// leading run that already reaches the image's high-water mark reads as complete when later
|
// leading run that already reaches the image's high-water mark reads as complete when later
|
||||||
// pieces are still missing - unreachable, because nothing reads between the pieces of one verb,
|
// pieces are still missing - unreachable, because nothing reads between the pieces of one verb,
|
||||||
@@ -502,7 +502,7 @@ namespace MobileGL::MG_Record {
|
|||||||
|
|
||||||
// The calling thread's SESSION's levels (every group of it - the callers are a session's
|
// The calling thread's SESSION's levels (every group of it - the callers are a session's
|
||||||
// context teardown and its applier release), or every level on a thread that is no
|
// context teardown and its applier release), or every level on a thread that is no
|
||||||
// session's. A live neighbour session's declared levels are not this caller's to drop:
|
// session's. A live neighbor session's declared levels are not this caller's to drop:
|
||||||
// that is the P14 Fatal StagedShadow.h's StagedBucket describes.
|
// that is the P14 Fatal StagedShadow.h's StagedBucket describes.
|
||||||
void DropAll() {
|
void DropAll() {
|
||||||
if (!m_any.load(std::memory_order_acquire)) return;
|
if (!m_any.load(std::memory_order_acquire)) return;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend {
|
namespace MobileGL::MG_Backend {
|
||||||
// SHARED IMAGES: server-allocated colour
|
// SHARED IMAGES: server-allocated color
|
||||||
// buffers exported to clients as dma-buf descriptors.
|
// 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
|
// The server-side view of one image, as a backend sees it: `NativeBuffer` is the image's
|
||||||
@@ -42,7 +42,7 @@ namespace MobileGL::MG_Backend {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// An import of a two-plane (YUV) dma-buf: where its planes are in the one descriptor, and
|
// 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).
|
// EGL_EXT_image_dma_buf_import's color hints (0 = not given).
|
||||||
struct SharedImageImportLayout {
|
struct SharedImageImportLayout {
|
||||||
Uint32 PlaneCount = 1;
|
Uint32 PlaneCount = 1;
|
||||||
Uint32 Offset[2] = {0, 0};
|
Uint32 Offset[2] = {0, 0};
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ static void bench_multi_draw_elements_base_vertex(GLenum mode, const GLsizei* co
|
|||||||
* glFinish and glFlush as no-ops (MG_Impl/GLImpl/Exporting/Definitions.cpp),
|
* glFinish and glFlush as no-ops (MG_Impl/GLImpl/Exporting/Definitions.cpp),
|
||||||
* so a glFinish-paced loop would time only the CPU-side submit on a MobileGL
|
* so a glFinish-paced loop would time only the CPU-side submit on a MobileGL
|
||||||
* backend while timing submit-plus-GPU on the native driver - the two numbers
|
* backend while timing submit-plus-GPU on the native driver - the two numbers
|
||||||
* would not describe the same work. A sync object is honoured by every stack
|
* would not describe the same work. A sync object is honored by every stack
|
||||||
* measured here.
|
* measured here.
|
||||||
*/
|
*/
|
||||||
typedef void (*case_fn)(int frame, long a, long b);
|
typedef void (*case_fn)(int frame, long a, long b);
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ static void case_mc_use_program(int frame, long a, long b) {
|
|||||||
|
|
||||||
/* ---- the case table both harnesses iterate --------------------------------
|
/* ---- the case table both harnesses iterate --------------------------------
|
||||||
* a/b are the case's own knobs; opsPerFrame is what one bench frame is
|
* a/b are the case's own knobs; opsPerFrame is what one bench frame is
|
||||||
* normalised by, so ns_per_op compares across renderers. The mc_* rates are
|
* normalized by, so ns_per_op compares across renderers. The mc_* rates are
|
||||||
* the per-frame call counts measured from the captured traces.
|
* the per-frame call counts measured from the captured traces.
|
||||||
*/
|
*/
|
||||||
typedef void (*bench_case_fn)(int frame, long a, long b);
|
typedef void (*bench_case_fn)(int frame, long a, long b);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// at glCompileShader - a different entry point from the one L1
|
// at glCompileShader - a different entry point from the one L1
|
||||||
// memoizes - and fresh shader objects meant ShaderCompileAdoptionMap
|
// memoizes - and fresh shader objects meant ShaderCompileAdoptionMap
|
||||||
// could not hand the earlier parse over either. L1c is what closed
|
// could not hand the earlier parse over either. L1c is what closed
|
||||||
// that: the compile half of the memo recognises each stage's source
|
// that: the compile half of the memo recognizes each stage's source
|
||||||
// and publishes its verdict without parsing, so on a hit this case now
|
// and publishes its verdict without parsing, so on a hit this case now
|
||||||
// constructs no glslang object at all.
|
// constructs no glslang object at all.
|
||||||
//
|
//
|
||||||
@@ -405,7 +405,7 @@ BENCHMARK(BM_EsslTranspile_CacheOn)->Arg(0)->Arg(120)->Unit(benchmark::kMicrosec
|
|||||||
// shows up here and nowhere else.
|
// shows up here and nowhere else.
|
||||||
//
|
//
|
||||||
// The distinct fragment sources also churn both front-end levels through their FIFO caps,
|
// The distinct fragment sources also churn both front-end levels through their FIFO caps,
|
||||||
// which is the eviction behaviour a real shaderpack load produces; over a long run the
|
// which is the eviction behavior a real shaderpack load produces; over a long run the
|
||||||
// constant vertex entry is occasionally evicted by that churn and re-inserted, so the L1c
|
// constant vertex entry is occasionally evicted by that churn and re-inserted, so the L1c
|
||||||
// hit rate reported below is high but not exactly 1.0 per iteration.
|
// hit rate reported below is high but not exactly 1.0 per iteration.
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// zero-pass Optimizer::Run and a bare BuildModule on the same binary, so the FIXED
|
// zero-pass Optimizer::Run and a bare BuildModule on the same binary, so the FIXED
|
||||||
// parse/serialize overhead can be separated from the work the passes actually do. It also
|
// parse/serialize overhead can be separated from the work the passes actually do. It also
|
||||||
// runs the same pass set merged onto ONE Optimizer, which is the saving a merged chain
|
// runs the same pass set merged onto ONE Optimizer, which is the saving a merged chain
|
||||||
// would realise.
|
// would realize.
|
||||||
//
|
//
|
||||||
// Measurement only: it links MobileGL_s and drives the public ShaderCompiler API, so it
|
// Measurement only: it links MobileGL_s and drives the public ShaderCompiler API, so it
|
||||||
// needs no GL context and no driver. The driver's own glCompileShader/glLinkProgram is
|
// needs no GL context and no driver. The driver's own glCompileShader/glLinkProgram is
|
||||||
@@ -746,7 +746,7 @@ void main() {
|
|||||||
Emit(name, "program", "glslang.GlslangToSpv (both stages)", "frontend", 0, inner);
|
Emit(name, "program", "glslang.GlslangToSpv (both stages)", "frontend", 0, inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- build the artefacts every later measurement runs against ----
|
// ---- build the artifacts every later measurement runs against ----
|
||||||
BuiltProgram built;
|
BuiltProgram built;
|
||||||
{
|
{
|
||||||
auto shaders = ParseBoth(vsPre, fsPre, env);
|
auto shaders = ParseBoth(vsPre, fsPre, env);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
// End of Source File Header
|
// End of Source File Header
|
||||||
|
|
||||||
// mobilegl_gbm.so: a GBM backend (the loader's backend ABI, gbm_backend_abi.h) whose buffer
|
// mobilegl_gbm.so: a GBM backend (the loader's backend ABI, gbm_backend_abi.h) whose buffer
|
||||||
// objects are MobileGL shared images - colour buffers the MobileGL server allocates and exports
|
// objects are MobileGL shared images - color buffers the MobileGL server allocates and exports
|
||||||
// as dma-bufs. Selected with
|
// as dma-bufs. Selected with
|
||||||
// GBM_BACKEND=mobilegl; the loader then finds <dir>/mobilegl_gbm.so on its backend path.
|
// GBM_BACKEND=mobilegl; the loader then finds <dir>/mobilegl_gbm.so on its backend path.
|
||||||
//
|
//
|
||||||
@@ -54,7 +54,7 @@ namespace {
|
|||||||
constexpr uint64_t kModifierLinear = 0;
|
constexpr uint64_t kModifierLinear = 0;
|
||||||
constexpr uint64_t kModifierInvalid = 0x00ffffffffffffffull;
|
constexpr uint64_t kModifierInvalid = 0x00ffffffffffffffull;
|
||||||
|
|
||||||
// Usages no shared image can honour: a CPU-written cursor (bo_write), a guaranteed-linear
|
// Usages no shared image can honor: a CPU-written cursor (bo_write), a guaranteed-linear
|
||||||
// layout, protected content. Scanout/rendering/texturing are accepted - every caller of
|
// layout, protected content. Scanout/rendering/texturing are accepted - every caller of
|
||||||
// gbm_bo_create passes them, and a shared image serves all three.
|
// gbm_bo_create passes them, and a shared image serves all three.
|
||||||
constexpr uint32_t kRefusedUsage = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE | GBM_BO_USE_LINEAR | GBM_BO_USE_PROTECTED;
|
constexpr uint32_t kRefusedUsage = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE | GBM_BO_USE_LINEAR | GBM_BO_USE_PROTECTED;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
|
|||||||
"EGL_MESA_platform_surfaceless" MOBILEGL_PLATFORM_WAYLAND_EXTENSIONS;
|
"EGL_MESA_platform_surfaceless" MOBILEGL_PLATFORM_WAYLAND_EXTENSIONS;
|
||||||
// The display list again, with the dma-buf import a backend with shared images has (a split
|
// The display list again, with the dma-buf import a backend with shared images has (a split
|
||||||
// client: the server allocates the images and names the descriptors that come back). A
|
// client: the server allocates the images and names the descriptors that come back). A
|
||||||
// monolith has no allocator to recognise a dma-buf with, so it never advertises these. The
|
// monolith has no allocator to recognize a dma-buf with, so it never advertises these. The
|
||||||
// same server answers the buffer age of its surfaces and takes swap damage to its presents.
|
// same server answers the buffer age of its surfaces and takes swap damage to its presents.
|
||||||
inline constexpr const char* kDisplayExtensionStringWithSharedImages =
|
inline constexpr const char* kDisplayExtensionStringWithSharedImages =
|
||||||
"EGL_KHR_create_context EGL_KHR_surfaceless_context EGL_KHR_no_config_context EGL_EXT_platform_base "
|
"EGL_KHR_create_context EGL_KHR_surfaceless_context EGL_KHR_no_config_context EGL_EXT_platform_base "
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace MobileGL::MG_Impl::EGLImpl::Wayland {
|
|||||||
inline constexpr EGLenum kPlatformWayland = 0x31D8;
|
inline constexpr EGLenum kPlatformWayland = 0x31D8;
|
||||||
|
|
||||||
// Whether a display is a Wayland one: asked for as EGL_PLATFORM_WAYLAND, or (eglGetDisplay with
|
// Whether a display is a Wayland one: asked for as EGL_PLATFORM_WAYLAND, or (eglGetDisplay with
|
||||||
// no platform) a native display that is a wl_display - recognised the way EGL loaders usually do, by its
|
// no platform) a native display that is a wl_display - recognized the way EGL loaders usually do, by its
|
||||||
// first word being libwayland-client's wl_display_interface (or, for an application with its
|
// first word being libwayland-client's wl_display_interface (or, for an application with its
|
||||||
// own copy of libwayland, an interface named "wl_display").
|
// own copy of libwayland, an interface named "wl_display").
|
||||||
Bool IsWaylandDisplay(Uint64 nativeDisplay, EGLenum platform);
|
Bool IsWaylandDisplay(Uint64 nativeDisplay, EGLenum platform);
|
||||||
|
|||||||
@@ -412,7 +412,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
break;
|
break;
|
||||||
case GL_BUFFER_ACCESS_FLAGS:
|
case GL_BUFFER_ACCESS_FLAGS:
|
||||||
// The MapBufferRange flags verbatim; glMapBuffer's access enum has already been
|
// The MapBufferRange flags verbatim; glMapBuffer's access enum has already been
|
||||||
// normalised into the same bits. Zero while the buffer is not mapped.
|
// normalized into the same bits. Zero while the buffer is not mapped.
|
||||||
*params = bufferObject->IsMapped() ? static_cast<GLint>(MG_Util::ConvertBufferMappingAccessToGLEnum(
|
*params = bufferObject->IsMapped() ? static_cast<GLint>(MG_Util::ConvertBufferMappingAccessToGLEnum(
|
||||||
bufferObject->GetMappingAccess()))
|
bufferObject->GetMappingAccess()))
|
||||||
: 0;
|
: 0;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whether `name` currently names an object of `identifier`'s type. GL 4.6 core 20.5 makes
|
// Whether `name` currently names an object of `identifier`'s type. GL 4.6 core 20.5 makes
|
||||||
// labelling something that does not exist INVALID_VALUE, and every type KHR_debug lists
|
// labeling something that does not exist INVALID_VALUE, and every type KHR_debug lists
|
||||||
// has a frontend name check - so this is answered exactly rather than waved through.
|
// has a frontend name check - so this is answered exactly rather than waved through.
|
||||||
// GL_DISPLAY_LIST is deliberately absent: it exists only in the compatibility profile,
|
// GL_DISPLAY_LIST is deliberately absent: it exists only in the compatibility profile,
|
||||||
// which MobileGL does not expose, so it falls to the INVALID_ENUM path below.
|
// which MobileGL does not expose, so it falls to the INVALID_ENUM path below.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// * glObjectLabel names a FRONTEND object. MobileGL's texture 5 is not the ES driver's
|
// * glObjectLabel names a FRONTEND object. MobileGL's texture 5 is not the ES driver's
|
||||||
// texture 5 (and under DirectVulkan it is not a driver object at all), so forwarding the
|
// texture 5 (and under DirectVulkan it is not a driver object at all), so forwarding the
|
||||||
// pair verbatim would label an unrelated object or a nonexistent one - worse than not
|
// pair verbatim would label an unrelated object or a nonexistent one - worse than not
|
||||||
// labelling.
|
// labeling.
|
||||||
// * A debug GROUP is only meaningful if it brackets the commands the application issued
|
// * A debug GROUP is only meaningful if it brackets the commands the application issued
|
||||||
// inside it. Neither backend emits its work at the moment the GL call arrives: DirectGLES
|
// inside it. Neither backend emits its work at the moment the GL call arrives: DirectGLES
|
||||||
// defers and reorders state sync and uploads around draws, and DirectVulkan is usually not
|
// defers and reorders state sync and uploads around draws, and DirectVulkan is usually not
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// Draws without a geometry stage write exactly the primitives they assemble,
|
// Draws without a geometry stage write exactly the primitives they assemble,
|
||||||
// clamped by the capture buffers' remaining capacity (a full buffer stops
|
// clamped by the capture buffers' remaining capacity (a full buffer stops
|
||||||
// recording whole primitives, which is what PRIMITIVES_WRITTEN reports).
|
// recording whole primitives, which is what PRIMITIVES_WRITTEN reports).
|
||||||
// Geometry amplification is not modelled here.
|
// Geometry amplification is not modeled here.
|
||||||
static void AccountTransformFeedbackPrimitives(GLenum mode, GLsizei count) {
|
static void AccountTransformFeedbackPrimitives(GLenum mode, GLsizei count) {
|
||||||
if (!MG_State::pGLContext->IsTransformFeedbackActive()) return;
|
if (!MG_State::pGLContext->IsTransformFeedbackActive()) return;
|
||||||
// A paused span captures nothing, so a draw made while paused contributes to
|
// A paused span captures nothing, so a draw made while paused contributes to
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// because a capability recorded for one of them says nothing about the others: DirectGLES
|
// because a capability recorded for one of them says nothing about the others: DirectGLES
|
||||||
// decides each target's substitution against that target's own probe, and a buffer texture
|
// decides each target's substitution against that target's own probe, and a buffer texture
|
||||||
// never gets one at all. This is also where the three-channel widening becomes visible to
|
// never gets one at all. This is also where the three-channel widening becomes visible to
|
||||||
// the application - a GL_RGB8_SNORM colour attachment on a driver with no renderable
|
// the application - a GL_RGB8_SNORM color attachment on a driver with no renderable
|
||||||
// three-channel format answers COMPLETE because the backend stores it as GL_RGBA16F and
|
// three-channel format answers COMPLETE because the backend stores it as GL_RGBA16F and
|
||||||
// recorded FramebufferRenderable in CaveatCaps.
|
// recorded FramebufferRenderable in CaveatCaps.
|
||||||
Bool IsColorInternalFormatRenderable(TextureInternalFormat format, SizeT capabilityTargetIndex) {
|
Bool IsColorInternalFormatRenderable(TextureInternalFormat format, SizeT capabilityTargetIndex) {
|
||||||
@@ -502,9 +502,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!FramebufferImpl::ValidateColorAttachmentInRange(attachmentType, functionName)) return false;
|
if (!FramebufferImpl::ValidateColorAttachmentInRange(attachmentType, functionName)) return false;
|
||||||
// "An INVALID_OPERATION error is generated if zero is bound to target." MobileGL keeps
|
// "An INVALID_OPERATION error is generated if zero is bound to target." MobileGL keeps
|
||||||
// a real FramebufferObject for framebuffer 0, so a null test can never see this - the
|
// a real FramebufferObject for framebuffer 0, so a null test can never see this - the
|
||||||
// object is always there, and framebuffer 0 has to be recognised by identity instead,
|
// object is always there, and framebuffer 0 has to be recognized by identity instead,
|
||||||
// the same comparison DrawBuffers_State makes. Without this an attach onto the default
|
// the same comparison DrawBuffers_State makes. Without this an attach onto the default
|
||||||
// framebuffer silently REPLACED its colour attachment, permanently desynchronising it
|
// framebuffer silently REPLACED its color attachment, permanently desynchronising it
|
||||||
// from what the swapchain keeps publishing.
|
// from what the swapchain keeps publishing.
|
||||||
const auto& defaultFramebufferInfo = FramebufferImpl::pDefaultFramebufferInfo;
|
const auto& defaultFramebufferInfo = FramebufferImpl::pDefaultFramebufferInfo;
|
||||||
if (!framebufferObject ||
|
if (!framebufferObject ||
|
||||||
@@ -568,12 +568,12 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// shorthand for attaching the same image to both halves (GL 4.6 core 9.2.6), so
|
// shorthand for attaching the same image to both halves (GL 4.6 core 9.2.6), so
|
||||||
// whether glFramebufferTexture made it LAYERED is a property of the call, not of
|
// whether glFramebufferTexture made it LAYERED is a property of the call, not of
|
||||||
// which half is being recorded - and dropping it here (the parameter defaults to
|
// which half is being recorded - and dropping it here (the parameter defaults to
|
||||||
// false) recorded a non-layered depth/stencil attachment beside a layered colour
|
// false) recorded a non-layered depth/stencil attachment beside a layered color
|
||||||
// one for every layered target. That is an inconsistent framebuffer by 9.4.1's
|
// one for every layered target. That is an inconsistent framebuffer by 9.4.1's
|
||||||
// own rule, and downstream it means the depth/stencil attachment covers layer 0
|
// own rule, and downstream it means the depth/stencil attachment covers layer 0
|
||||||
// alone: DirectVulkan built its view with layerCount 1 under a framebuffer
|
// alone: DirectVulkan built its view with layerCount 1 under a framebuffer
|
||||||
// declaring N layers (VUID-VkFramebufferCreateInfo-flags-04535), and DirectGLES
|
// declaring N layers (VUID-VkFramebufferCreateInfo-flags-04535), and DirectGLES
|
||||||
// attached one layer of it beside a layered colour target, which the driver
|
// attached one layer of it beside a layered color target, which the driver
|
||||||
// answers with GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS - every draw silently
|
// answers with GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS - every draw silently
|
||||||
// produced nothing. This is the shape
|
// produced nothing. This is the shape
|
||||||
// texture_cube_map_array.stencil_attachments_*_layered and
|
// texture_cube_map_array.stencil_attachments_*_layered and
|
||||||
@@ -1654,7 +1654,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Everything above is the spec's error set and is answered for every target and every layer
|
// Everything above is the spec's error set and is answered for every target and every layer
|
||||||
// on every backend. Whether the attachment can actually be honoured is a backend question:
|
// on every backend. Whether the attachment can actually be honored is a backend question:
|
||||||
// DirectGLES hands the layer to glFramebufferTextureLayer and renders to it, while
|
// DirectGLES hands the layer to glFramebufferTextureLayer and renders to it, while
|
||||||
// DirectVulkan maps a GL layer onto a Vulkan array layer with no notion of a 3D depth slice,
|
// DirectVulkan maps a GL layer onto a Vulkan array layer with no notion of a 3D depth slice,
|
||||||
// so a slice lands outside the image and the renderer asserts on the clear. Letting it
|
// so a slice lands outside the image and the renderer asserts on the clear. Letting it
|
||||||
@@ -1904,7 +1904,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
isMultiBufferName ? ErrorCode::InvalidOperation : ErrorCode::InvalidEnum,
|
isMultiBufferName ? ErrorCode::InvalidOperation : ErrorCode::InvalidEnum,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
std::format("`src` = {} does not name a single readable colour buffer.",
|
std::format("`src` = {} does not name a single readable color buffer.",
|
||||||
MG_Util::ConvertGLEnumToString(src))));
|
MG_Util::ConvertGLEnumToString(src))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1918,7 +1918,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// Naming a buffer the other kind of framebuffer has is INVALID_OPERATION rather than
|
// Naming a buffer the other kind of framebuffer has is INVALID_OPERATION rather than
|
||||||
// INVALID_ENUM (GL 4.6 core 17.4.1) - the name is accepted, this framebuffer just has no
|
// INVALID_ENUM (GL 4.6 core 17.4.1) - the name is accepted, this framebuffer just has no
|
||||||
// such colour buffer.
|
// such color buffer.
|
||||||
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
||||||
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
|
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
@@ -2060,7 +2060,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// Which buffers the integer clears accept is narrower than the float one, and differs between
|
// Which buffers the integer clears accept is narrower than the float one, and differs between
|
||||||
// them: signed values can clear COLOR or STENCIL, unsigned only COLOR (GL 4.6 core 17.4.3.1).
|
// them: signed values can clear COLOR or STENCIL, unsigned only COLOR (GL 4.6 core 17.4.3.1).
|
||||||
// Only the colour buffer is indexed; a stencil clear names the single stencil buffer, so any
|
// Only the color buffer is indexed; a stencil clear names the single stencil buffer, so any
|
||||||
// drawbuffer other than 0 is out of range rather than merely unused.
|
// drawbuffer other than 0 is out of range rather than merely unused.
|
||||||
Bool ValidateNamedClearIntegerv_State(GLenum buffer, GLint drawbuffer, const void* value, Bool allowStencil,
|
Bool ValidateNamedClearIntegerv_State(GLenum buffer, GLint drawbuffer, const void* value, Bool allowStencil,
|
||||||
const char* caller) {
|
const char* caller) {
|
||||||
@@ -2121,7 +2121,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// glInvalidateFramebuffer and its three siblings only grant the implementation permission to
|
// glInvalidateFramebuffer and its three siblings only grant the implementation permission to
|
||||||
// throw the named attachments' contents away - "become undefined" is satisfied by keeping them
|
// throw the named attachments' contents away - "become undefined" is satisfied by keeping them
|
||||||
// - so MobileGL validates the call and leaves the contents alone. Discarding is a bandwidth
|
// - so MobileGL validates the call and leaves the contents alone. Discarding is a bandwidth
|
||||||
// optimisation that would need a backend dependency; it can be added later without changing
|
// optimization that would need a backend dependency; it can be added later without changing
|
||||||
// what any of these entry points promise. The conformance tests exercise the validation, which
|
// what any of these entry points promise. The conformance tests exercise the validation, which
|
||||||
// is the part that was missing.
|
// is the part that was missing.
|
||||||
Bool ValidateInvalidateAttachments_State(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
Bool ValidateInvalidateAttachments_State(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
|
||||||
@@ -2144,7 +2144,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (isDefaultFramebuffer) {
|
if (isDefaultFramebuffer) {
|
||||||
switch (attachment) {
|
switch (attachment) {
|
||||||
// The by-name forms name the default framebuffer's buffers the way
|
// The by-name forms name the default framebuffer's buffers the way
|
||||||
// glClearNamedFramebuffer does, with COLOR standing for the colour buffer, while
|
// glClearNamedFramebuffer does, with COLOR standing for the color buffer, while
|
||||||
// the target forms use the individual FRONT_LEFT/BACK_RIGHT tokens. Both spellings
|
// the target forms use the individual FRONT_LEFT/BACK_RIGHT tokens. Both spellings
|
||||||
// reach here, so both are accepted (GL 4.6 core 17.4.4).
|
// reach here, so both are accepted (GL 4.6 core 17.4.4).
|
||||||
case GL_COLOR:
|
case GL_COLOR:
|
||||||
@@ -3341,7 +3341,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Depth and stencil have no meaningful interpolation, so GL_LINEAR is rejected outright
|
// Depth and stencil have no meaningful interpolation, so GL_LINEAR is rejected outright
|
||||||
// rather than downgraded - even when the mask also carries the colour bit.
|
// rather than downgraded - even when the mask also carries the color bit.
|
||||||
if (filter == GL_LINEAR && (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
if (filter == GL_LINEAR && (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
|||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeUnique<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl/FramebufferImpl", caller,
|
"MG_Impl/GLImpl/FramebufferImpl", caller,
|
||||||
std::format("Colour attachment {} is beyond GL_MAX_COLOR_ATTACHMENTS ({}).", colorIndex, limit)));
|
std::format("Color attachment {} is beyond GL_MAX_COLOR_ATTACHMENTS ({}).", colorIndex, limit)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
|
|||||||
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
Bool ValidateFramebufferAttachmentType(FramebufferAttachmentType attachment);
|
||||||
// GL_COLOR_ATTACHMENTn is a token per n up to 31, but only the first GL_MAX_COLOR_ATTACHMENTS of
|
// GL_COLOR_ATTACHMENTn is a token per n up to 31, but only the first GL_MAX_COLOR_ATTACHMENTS of
|
||||||
// them name an attachment point of a framebuffer object; the rest are INVALID_OPERATION for the
|
// them name an attachment point of a framebuffer object; the rest are INVALID_OPERATION for the
|
||||||
// attaching entry points (GL 4.6 core 9.2.7). Non-colour attachments pass through unchanged.
|
// attaching entry points (GL 4.6 core 9.2.7). Non-color attachments pass through unchanged.
|
||||||
Bool ValidateColorAttachmentInRange(FramebufferAttachmentType attachment, const char* caller);
|
Bool ValidateColorAttachmentInRange(FramebufferAttachmentType attachment, const char* caller);
|
||||||
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
Bool ValidateRenderbufferTarget(RenderbufferTarget target);
|
||||||
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
Bool ValidateRenderbufferName(Uint index, Bool allowZero = true);
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// glGetSubroutineIndex / glUniformSubroutinesuiv, only the program-interface enum
|
// glGetSubroutineIndex / glUniformSubroutinesuiv, only the program-interface enum
|
||||||
// plumbing. These are answered - with the GL 4.5 core minimums - because the conformance
|
// plumbing. These are answered - with the GL 4.5 core minimums - because the conformance
|
||||||
// suite queries them before it checks for the feature and an INVALID_ENUM both leaves the
|
// suite queries them before it checks for the feature and an INVALID_ENUM both leaves the
|
||||||
// caller reading its own uninitialised stack slot and strands an error for the next
|
// caller reading its own uninitialized stack slot and strands an error for the next
|
||||||
// unrelated call to trip over. The extension is deliberately NOT advertised, so the
|
// unrelated call to trip over. The extension is deliberately NOT advertised, so the
|
||||||
// numbers are a table entry, not a capability claim.
|
// numbers are a table entry, not a capability claim.
|
||||||
constexpr GLint kFrontendMaxSubroutines = 256;
|
constexpr GLint kFrontendMaxSubroutines = 256;
|
||||||
@@ -1542,7 +1542,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
//
|
//
|
||||||
// The POINTER-valued macro, so the init-statement below is unchanged in a pull
|
// The POINTER-valued macro, so the init-statement below is unchanged in a pull
|
||||||
// build and G1 cannot see this edit: the Bool-valued spelling moved this
|
// build and G1 cannot see this edit: the Bool-valued spelling moved this
|
||||||
// function by -150 bytes for no behavioural reason at all.
|
// function by -150 bytes for no behavioral reason at all.
|
||||||
if (const auto getGpuTimestampNs =
|
if (const auto getGpuTimestampNs =
|
||||||
MGL_BACKEND_SLOT_PTR_CAP(GetGpuTimestampNs, MG_Pipe::kCapTimerQuery)) {
|
MGL_BACKEND_SLOT_PTR_CAP(GetGpuTimestampNs, MG_Pipe::kCapTimerQuery)) {
|
||||||
MGP_FILL(GetGpuTimestampNs);
|
MGP_FILL(GetGpuTimestampNs);
|
||||||
@@ -2584,7 +2584,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
//
|
//
|
||||||
// The POINTER-valued macro, so the init-statement below is unchanged in a pull
|
// The POINTER-valued macro, so the init-statement below is unchanged in a pull
|
||||||
// build and G1 cannot see this edit: the Bool-valued spelling moved this
|
// build and G1 cannot see this edit: the Bool-valued spelling moved this
|
||||||
// function by -150 bytes for no behavioural reason at all.
|
// function by -150 bytes for no behavioral reason at all.
|
||||||
if (const auto getGpuTimestampNs =
|
if (const auto getGpuTimestampNs =
|
||||||
MGL_BACKEND_SLOT_PTR_CAP(GetGpuTimestampNs, MG_Pipe::kCapTimerQuery)) {
|
MGL_BACKEND_SLOT_PTR_CAP(GetGpuTimestampNs, MG_Pipe::kCapTimerQuery)) {
|
||||||
MGP_FILL(GetGpuTimestampNs);
|
MGP_FILL(GetGpuTimestampNs);
|
||||||
|
|||||||
@@ -573,7 +573,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLuint CreateShader_State(GLenum type) {
|
GLuint CreateShader_State(GLenum type) {
|
||||||
// GL 4.6 core 7.1: shaderType is an enum, so an unrecognised one is INVALID_ENUM (it
|
// GL 4.6 core 7.1: shaderType is an enum, so an unrecognized one is INVALID_ENUM (it
|
||||||
// used to be documented as INVALID_VALUE). The check has to happen HERE: the state
|
// used to be documented as INVALID_VALUE). The check has to happen HERE: the state
|
||||||
// layer hands out a name for ShaderStage::Unknown just as happily as for a real
|
// layer hands out a name for ShaderStage::Unknown just as happily as for a real
|
||||||
// stage, so the old "shaderId == 0 means bad type" test could never fire and an
|
// stage, so the old "shaderId == 0 means bad type" test could never fire and an
|
||||||
@@ -3324,7 +3324,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
void GetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount,
|
||||||
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
const GLenum* props, GLsizei bufSize, GLsizei* length, GLint* params) {
|
||||||
// Every early-out below reports "nothing was written", and it has to say so before it can
|
// Every early-out below reports "nothing was written", and it has to say so before it can
|
||||||
// take one: callers legitimately leave *length uninitialised and then loop to it. The CTS
|
// take one: callers legitimately leave *length uninitialized and then loop to it. The CTS
|
||||||
// does exactly that (gl4cProgramInterfaceQueryTests.cpp:2172 declares `GLsizei length;` and
|
// does exactly that (gl4cProgramInterfaceQueryTests.cpp:2172 declares `GLsizei length;` and
|
||||||
// walks `for (i = 0; i < length; ++i)` over a 1000-entry stack array), so an untouched
|
// walks `for (i = 0; i < length; ++i)` over a 1000-entry stack array), so an untouched
|
||||||
// *length turned every error path here into a stack overrun inside the caller -
|
// *length turned every error path here into a stack overrun inside the caller -
|
||||||
@@ -3414,7 +3414,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// already carries, so this is a rename of glGetProgramResourceiv's props onto the older
|
// already carries, so this is a rename of glGetProgramResourceiv's props onto the older
|
||||||
// entry point's - and the two are required to agree, which is only true while both read the
|
// entry point's - and the two are required to agree, which is only true while both read the
|
||||||
// same model. It was a silent stub: it wrote nothing, raised nothing, and left every probe
|
// same model. It was a silent stub: it wrote nothing, raised nothing, and left every probe
|
||||||
// reading its own uninitialised output.
|
// reading its own uninitialized output.
|
||||||
static Bool TryMapActiveAtomicCounterBufferProp(GLenum pname, GLenum& outProp) {
|
static Bool TryMapActiveAtomicCounterBufferProp(GLenum pname, GLenum& outProp) {
|
||||||
switch (pname) {
|
switch (pname) {
|
||||||
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
|
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
|
||||||
@@ -3547,7 +3547,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// raise is one of theirs, raised at the point they would raise it.
|
// raise is one of theirs, raised at the point they would raise it.
|
||||||
GLuint CreateShaderProgramv(GLenum type, GLsizei count, const GLchar* const* strings) {
|
GLuint CreateShaderProgramv(GLenum type, GLsizei count, const GLchar* const* strings) {
|
||||||
// GL 4.6 core 7.3: a negative count is INVALID_VALUE and is checked before anything
|
// GL 4.6 core 7.3: a negative count is INVALID_VALUE and is checked before anything
|
||||||
// is created, so a bad count never leaks a shader name. An unrecognised type is
|
// is created, so a bad count never leaks a shader name. An unrecognized type is
|
||||||
// INVALID_ENUM, which CreateShader_State raises below.
|
// INVALID_ENUM, which CreateShader_State raises below.
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GL_EXT_fragment_shading_rate 14.X.1: the only error is a rate outside table X.1, and the
|
// GL_EXT_fragment_shading_rate 14.X.1: the only error is a rate outside table X.1, and the
|
||||||
// state is left untouched by it. Whether the device can honour the rate is not an error -
|
// state is left untouched by it. Whether the device can honor the rate is not an error -
|
||||||
// an unsupported rate is clamped at rasterization, which the backends leave to the driver.
|
// an unsupported rate is clamped at rasterization, which the backends leave to the driver.
|
||||||
void ShadingRateEXT_State(GLenum rate) {
|
void ShadingRateEXT_State(GLenum rate) {
|
||||||
const Uint8 packed = MGPackShadingRate(rate);
|
const Uint8 packed = MGPackShadingRate(rate);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Via GLint in both integer spellings: a direct float -> GLuint cast of a negative value
|
// Via GLint in both integer spellings: a direct float -> GLuint cast of a negative value
|
||||||
// (GL_TEXTURE_MIN_LOD defaults to -1000) is undefined behaviour, while the two-step
|
// (GL_TEXTURE_MIN_LOD defaults to -1000) is undefined behavior, while the two-step
|
||||||
// conversion is the well-defined modular one, and it is what the texture-side
|
// conversion is the well-defined modular one, and it is what the texture-side
|
||||||
// GetTexParameterIuiv fallback does.
|
// GetTexParameterIuiv fallback does.
|
||||||
const GLint asInt = static_cast<GLint>(value);
|
const GLint asInt = static_cast<GLint>(value);
|
||||||
@@ -86,7 +86,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_TEXTURE_MAX_LOD:
|
case GL_TEXTURE_MAX_LOD:
|
||||||
case GL_TEXTURE_LOD_BIAS:
|
case GL_TEXTURE_LOD_BIAS:
|
||||||
return true;
|
return true;
|
||||||
// Four components, and GL puts no range on them - a border colour outside [0,1] is
|
// Four components, and GL puts no range on them - a border color outside [0,1] is
|
||||||
// clamped when a fixed-point format is sampled, not rejected here. The scalar readers
|
// clamped when a fixed-point format is sampled, not rejected here. The scalar readers
|
||||||
// below would look at one component and invent an error.
|
// below would look at one component and invent an error.
|
||||||
case GL_TEXTURE_BORDER_COLOR:
|
case GL_TEXTURE_BORDER_COLOR:
|
||||||
@@ -182,7 +182,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
const auto* values = (const GLfloat*)param;
|
const auto* values = (const GLfloat*)param;
|
||||||
samplerObj->SetBorderColor(FloatVec4(values[0], values[1], values[2], values[3]));
|
samplerObj->SetBorderColor(FloatVec4(values[0], values[1], values[2], values[3]));
|
||||||
} else if (!isIntegerCommand) {
|
} else if (!isIntegerCommand) {
|
||||||
// glSamplerParameteriv: GL 4.6 core equation 2.2 into the FLOAT border colour.
|
// glSamplerParameteriv: GL 4.6 core equation 2.2 into the FLOAT border color.
|
||||||
const auto* values = (const GLint*)param;
|
const auto* values = (const GLint*)param;
|
||||||
samplerObj->SetBorderColor(FloatVec4(MG_Util::SignedNormalizedInt32ToFloat(values[0]),
|
samplerObj->SetBorderColor(FloatVec4(MG_Util::SignedNormalizedInt32ToFloat(values[0]),
|
||||||
MG_Util::SignedNormalizedInt32ToFloat(values[1]),
|
MG_Util::SignedNormalizedInt32ToFloat(values[1]),
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
|
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
|
||||||
// GL 4.6 core 4.1: a negative bufSize is INVALID_VALUE, an unnamed sync is INVALID_VALUE
|
// GL 4.6 core 4.1: a negative bufSize is INVALID_VALUE, an unnamed sync is INVALID_VALUE
|
||||||
// and an unrecognised pname is INVALID_ENUM. All three used to leave glGetError() clean
|
// and an unrecognized pname is INVALID_ENUM. All three used to leave glGetError() clean
|
||||||
// and write a plausible-looking zero, which is the one failure mode a caller cannot tell
|
// and write a plausible-looking zero, which is the one failure mode a caller cannot tell
|
||||||
// apart from a real answer - GL_SYNC_STATUS legitimately answers GL_UNSIGNALED (0x9118),
|
// apart from a real answer - GL_SYNC_STATUS legitimately answers GL_UNSIGNALED (0x9118),
|
||||||
// but a mistyped pname answered a bare 0 that no query ever returns.
|
// but a mistyped pname answered a bare 0 that no query ever returns.
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// glTexParameteriv(GL_TEXTURE_BORDER_COLOR): GL 4.6 core 8.10 sends the components through
|
// glTexParameteriv(GL_TEXTURE_BORDER_COLOR): GL 4.6 core 8.10 sends the components through
|
||||||
// equation 2.2 into the floating-point border colour. glGetTexParameteriv reverses it with
|
// equation 2.2 into the floating-point border color. glGetTexParameteriv reverses it with
|
||||||
// equation 2.3; the two live in one header so they cannot drift apart.
|
// equation 2.3; the two live in one header so they cannot drift apart.
|
||||||
void SetTextureBorderColorFromInts(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
void SetTextureBorderColorFromInts(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||||
const GLint* params) {
|
const GLint* params) {
|
||||||
@@ -582,7 +582,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// AT the category limit (BackendObject_DirectGLES's ProbeTextureSampleCounts) so its
|
// AT the category limit (BackendObject_DirectGLES's ProbeTextureSampleCounts) so its
|
||||||
// head can never exceed it, and max() therefore always collapsed to the category
|
// head can never exceed it, and max() therefore always collapsed to the category
|
||||||
// value. A format whose 4- and 2-sample probes fail inside a 4-sample category - a
|
// value. A format whose 4- and 2-sample probes fail inside a 4-sample category - a
|
||||||
// float colour format under EXT_color_buffer_float is the natural instance - was
|
// float color format under EXT_color_buffer_float is the natural instance - was
|
||||||
// still accepted at 4, silently squeezed to 1 by ClampSamplesToBackendSupport, and
|
// still accepted at 4, silently squeezed to 1 by ClampSamplesToBackendSupport, and
|
||||||
// then reported as 4 by GL_TEXTURE_SAMPLES while glGetInternalformativ said 1.
|
// then reported as 4 by GL_TEXTURE_SAMPLES while glGetInternalformativ said 1.
|
||||||
const Int probedMaxSamples = GetProbedMaxTextureSamples(textureTarget, textureInternalFormat);
|
const Int probedMaxSamples = GetProbedMaxTextureSamples(textureTarget, textureInternalFormat);
|
||||||
@@ -672,7 +672,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// Redefining level 0 of a texture that already had a base image drops the rest of the chain,
|
// Redefining level 0 of a texture that already had a base image drops the rest of the chain,
|
||||||
// which is exactly what AllocateLevel used to do implicitly for every level. Keeping that
|
// which is exactly what AllocateLevel used to do implicitly for every level. Keeping that
|
||||||
// behaviour for level 0 - and only for level 0 - is what makes the grow-only change safe:
|
// behavior for level 0 - and only for level 0 - is what makes the grow-only change safe:
|
||||||
// any level-0 respecification leaves the chain in precisely the state it would have had
|
// any level-0 respecification leaves the chain in precisely the state it would have had
|
||||||
// before, while an upload to level N no longer destroys the levels beneath it.
|
// before, while an upload to level N no longer destroys the levels beneath it.
|
||||||
//
|
//
|
||||||
@@ -1002,7 +1002,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// GL 4.6 core 8.6: CopyTexSubImage* is not affected by pixel-store state or by a bound
|
// GL 4.6 core 8.6: CopyTexSubImage* is not affected by pixel-store state or by a bound
|
||||||
// pack buffer, but the backend readback this borrows honours both. Neutralise them for the
|
// pack buffer, but the backend readback this borrows honors both. Neutralise them for the
|
||||||
// duration of the read and put them back afterwards.
|
// duration of the read and put them back afterwards.
|
||||||
class ScopedNeutralPackState {
|
class ScopedNeutralPackState {
|
||||||
public:
|
public:
|
||||||
@@ -1203,7 +1203,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The six pnames a texture object shares with a sampler object carry an enum VALUE, and an
|
// The six pnames a texture object shares with a sampler object carry an enum VALUE, and an
|
||||||
// unrecognised one is INVALID_ENUM. The texture path used to hand the value straight to
|
// unrecognized one is INVALID_ENUM. The texture path used to hand the value straight to
|
||||||
// ConvertGLEnumToSamplerWrapMode / ...FilterMode and throw the Unknown away, so
|
// ConvertGLEnumToSamplerWrapMode / ...FilterMode and throw the Unknown away, so
|
||||||
// glTexParameteri(GL_TEXTURE_WRAP_S, GL_RED) was silently accepted. Sampler objects have had
|
// glTexParameteri(GL_TEXTURE_WRAP_S, GL_RED) was silently accepted. Sampler objects have had
|
||||||
// exactly this validator all along; calling it here rather than writing a second one is also
|
// exactly this validator all along; calling it here rather than writing a second one is also
|
||||||
@@ -1348,7 +1348,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// every setter reaches" - and MGPTextureParams takes MinLod, MaxLod and LodBias off that
|
// every setter reaches" - and MGPTextureParams takes MinLod, MaxLod and LodBias off that
|
||||||
// object, so every glTexParameter that writes GL_TEXTURE_MIN_LOD / MAX_LOD / LOD_BIAS
|
// object, so every glTexParameter that writes GL_TEXTURE_MIN_LOD / MAX_LOD / LOD_BIAS
|
||||||
// landed on state nothing watched and the applier's record kept saying MinLod = 0.
|
// landed on state nothing watched and the applier's record kept saying MinLod = 0.
|
||||||
// Wrong pixels, not a lost optimisation.
|
// Wrong pixels, not a lost optimization.
|
||||||
//
|
//
|
||||||
// THE HOOK IS HERE RATHER THAN ON BumpVersion because MG_State/GLState/SamplerState is
|
// THE HOOK IS HERE RATHER THAN ON BumpVersion because MG_State/GLState/SamplerState is
|
||||||
// package C's after the tag; C.7 grants this file for exactly this class of path ("the
|
// package C's after the tag; C.7 grants this file for exactly this class of path ("the
|
||||||
@@ -1462,7 +1462,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// every setter reaches" - and MGPTextureParams takes MinLod, MaxLod and LodBias off that
|
// every setter reaches" - and MGPTextureParams takes MinLod, MaxLod and LodBias off that
|
||||||
// object, so every glTexParameter that writes GL_TEXTURE_MIN_LOD / MAX_LOD / LOD_BIAS
|
// object, so every glTexParameter that writes GL_TEXTURE_MIN_LOD / MAX_LOD / LOD_BIAS
|
||||||
// landed on state nothing watched and the applier's record kept saying MinLod = 0.
|
// landed on state nothing watched and the applier's record kept saying MinLod = 0.
|
||||||
// Wrong pixels, not a lost optimisation.
|
// Wrong pixels, not a lost optimization.
|
||||||
//
|
//
|
||||||
// THE HOOK IS HERE RATHER THAN ON BumpVersion because MG_State/GLState/SamplerState is
|
// THE HOOK IS HERE RATHER THAN ON BumpVersion because MG_State/GLState/SamplerState is
|
||||||
// package C's after the tag; C.7 grants this file for exactly this class of path ("the
|
// package C's after the tag; C.7 grants this file for exactly this class of path ("the
|
||||||
@@ -2700,9 +2700,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return MG_State::pGLContext->ValidateTextureObject(texture) ? GL_TRUE : GL_FALSE;
|
return MG_State::pGLContext->ValidateTextureObject(texture) ? GL_TRUE : GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every texture parameter but the border colour, for one resolved texture: up to four values,
|
// Every texture parameter but the border color, for one resolved texture: up to four values,
|
||||||
// as doubles because a double holds each enum, level and float this state stores exactly. False
|
// as doubles because a double holds each enum, level and float this state stores exactly. False
|
||||||
// after recording an error. The border colour converts differently for each query type (GL 4.6
|
// after recording an error. The border color converts differently for each query type (GL 4.6
|
||||||
// core 8.11.2), so each form answers it itself.
|
// core 8.11.2), so each form answers it itself.
|
||||||
static Bool QueryTextureParameter(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
|
static Bool QueryTextureParameter(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
|
||||||
Double (&values)[4], Uint& count, const char* caller) {
|
Double (&values)[4], Uint& count, const char* caller) {
|
||||||
@@ -2819,7 +2819,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
GLenum pname, GLint* params, const char* caller) {
|
GLenum pname, GLint* params, const char* caller) {
|
||||||
if (pname == GL_TEXTURE_BORDER_COLOR) {
|
if (pname == GL_TEXTURE_BORDER_COLOR) {
|
||||||
// The inverse of glTexParameteriv: GL 4.6 core equation 2.3 against equation 2.2 on the
|
// The inverse of glTexParameteriv: GL 4.6 core equation 2.3 against equation 2.2 on the
|
||||||
// write side (SetTextureBorderColorFromInts). The raw integer colour is the Iiv query's.
|
// write side (SetTextureBorderColorFromInts). The raw integer color is the Iiv query's.
|
||||||
const auto& borderColor = textureObject->GetBorderColor();
|
const auto& borderColor = textureObject->GetBorderColor();
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
params[i] = MG_Util::FloatToSignedNormalizedInt32(borderColor[i]);
|
params[i] = MG_Util::FloatToSignedNormalizedInt32(borderColor[i]);
|
||||||
@@ -3302,7 +3302,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// The eleven targets GL 4.6 core 18.3.2 accepts. GL_TEXTURE_BUFFER, the six cube FACE
|
// The eleven targets GL 4.6 core 18.3.2 accepts. GL_TEXTURE_BUFFER, the six cube FACE
|
||||||
// enums and every PROXY enum all convert to a TextureTarget this frontend recognises,
|
// enums and every PROXY enum all convert to a TextureTarget this frontend recognizes,
|
||||||
// so ValidateTextureTarget lets them through; here they are INVALID_ENUM.
|
// so ValidateTextureTarget lets them through; here they are INVALID_ENUM.
|
||||||
Bool ValidateCopyImageTarget(GLenum target, const char* endpointName) {
|
Bool ValidateCopyImageTarget(GLenum target, const char* endpointName) {
|
||||||
switch (target) {
|
switch (target) {
|
||||||
@@ -3786,7 +3786,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
const Int z = cubeFaces ? 0 : offset.z();
|
const Int z = cubeFaces ? 0 : offset.z();
|
||||||
const Int depth = cubeFaces ? 1 : size.z();
|
const Int depth = cubeFaces ? 1 : size.z();
|
||||||
// Subtractions rather than sums: offset + extent are application-supplied GLints, and a
|
// Subtractions rather than sums: offset + extent are application-supplied GLints, and a
|
||||||
// signed overflow is undefined behaviour a compiler may resolve by assuming the check passes.
|
// signed overflow is undefined behavior a compiler may resolve by assuming the check passes.
|
||||||
if (offset.x() < 0 || offset.y() < 0 || z < 0 || size.x() > levelSize.x() - offset.x() ||
|
if (offset.x() < 0 || offset.y() < 0 || z < 0 || size.x() > levelSize.x() - offset.x() ||
|
||||||
size.y() > levelSize.y() - offset.y() || depth > levelDepth - z) {
|
size.y() > levelSize.y() - offset.y() || depth > levelDepth - z) {
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
@@ -4421,7 +4421,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
//
|
//
|
||||||
// ProcessTexturePixelsDataPack performs NO format or type conversion: it sizes every texel with
|
// ProcessTexturePixelsDataPack performs NO format or type conversion: it sizes every texel with
|
||||||
// GetInternalBytesPerPixel(the TEXTURE's internal format) and memcpys the shadow rows verbatim,
|
// GetInternalBytesPerPixel(the TEXTURE's internal format) and memcpys the shadow rows verbatim,
|
||||||
// and it carries a standing TODO for the pixel-store parameters, so it honours only SwapBytes and
|
// and it carries a standing TODO for the pixel-store parameters, so it honors only SwapBytes and
|
||||||
// the bitmap LSBFirst path. Both facts are invisible from the outside, and both are dangerous:
|
// the bitmap LSBFirst path. Both facts are invisible from the outside, and both are dangerous:
|
||||||
//
|
//
|
||||||
// * a (format, type) narrower than the shadow's own texel makes the copy write MORE bytes than
|
// * a (format, type) narrower than the shadow's own texel makes the copy write MORE bytes than
|
||||||
@@ -4432,7 +4432,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// overflow but is still wrong data.
|
// overflow but is still wrong data.
|
||||||
// * a pack state that puts padding, a row-length override or a skip offset between rows is
|
// * a pack state that puts padding, a row-length override or a skip offset between rows is
|
||||||
// ignored outright, so the rows land at the wrong destination strides - while the GPU
|
// ignored outright, so the rows land at the wrong destination strides - while the GPU
|
||||||
// readback path (DirectGLES StoreClientRows, and DirectVulkan through it) honours all of it.
|
// readback path (DirectGLES StoreClientRows, and DirectVulkan through it) honors all of it.
|
||||||
// Same glGetTexImage call, two different destination layouts, decided by whether the texture
|
// Same glGetTexImage call, two different destination layouts, decided by whether the texture
|
||||||
// happens to have a GPU image.
|
// happens to have a GPU image.
|
||||||
//
|
//
|
||||||
@@ -4475,7 +4475,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
ErrorCode::InvalidOperation,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>(
|
MakeUnique<GenericErrorInfo>(
|
||||||
"MG_Impl/GLImpl", caller,
|
"MG_Impl/GLImpl", caller,
|
||||||
"The CPU-shadow readback path packs rows tightly and cannot honour a pixel-store state that "
|
"The CPU-shadow readback path packs rows tightly and cannot honor a pixel-store state that "
|
||||||
"adds row padding, a row-length override or a skip offset."));
|
"adds row padding, a row-length override or a skip offset."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -6100,7 +6100,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
|
|
||||||
// The backend publishes where its device really places the samples of each count (a
|
// The backend publishes where its device really places the samples of each count (a
|
||||||
// shader's gl_SamplePosition reads the same places). A count it could not determine keeps
|
// shader's gl_SamplePosition reads the same places). A count it could not determine keeps
|
||||||
// answering the pixel centre.
|
// answering the pixel center.
|
||||||
Float position[2] = {0.5f, 0.5f};
|
Float position[2] = {0.5f, 0.5f};
|
||||||
if (MG_Backend::pActiveBackendObject != nullptr) {
|
if (MG_Backend::pActiveBackendObject != nullptr) {
|
||||||
MG_Backend::pActiveBackendObject->GetDynamicParameters().GetSamplePosition(samples, static_cast<Int>(index),
|
MG_Backend::pActiveBackendObject->GetDynamicParameters().GetSamplePosition(samples, static_cast<Int>(index),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user