[Refactor] (Magma): route every frontend read through MGB_CTX - 164 arrow sites sed'd, 49 non-arrow lines converted (43 asserts keep their meaning as MGB_CTX_LIVE); pull build byte-identical

- Every MG_State::pGLContext-> in the seven DirectVulkan TUs becomes MGB_CTX->
  (DirectVulkan.cpp 12, BackendObject_DirectVulkan.cpp 2, UniformManager.cpp 14,
  VkClearManager.cpp 1, VkRenderPassManager.cpp 3, VkTextureManager.cpp 2,
  VulkanRenderer.cpp 130 occurrences on 127 lines); each TU includes
  <MG_Pipe/PipeInputsSwitch.h> right after its MG_State/GLState/Core.h include
  (VkRenderPassManager.cpp after its include block, it never included Core.h).
- The 43 MOBILEGL_ASSERT(pGLContext) / (pGLContext != nullptr) lines become
  MOBILEGL_ASSERT(MGB_CTX_LIVE, ...): identical in every INFO build (the macro is
  empty there) and still a null-context assert in a DEBUG build.
- The six code-bearing guards are like-for-like pointer tests in the pull arm:
  if (MGB_CTX_LIVE) at the two InvalidateCompileEnv sites, MGB_CTX_LIVE in the
  XFB query counter condition and the ternary that snapshots the paused-primitive
  counter, !MGB_CTX_LIVE in BeginXfbCaptureForDraw, MGB_CTX_LIVE && in the
  provoking-vertex resolve. No semantic rewrite: under push MGB_CTX_LIVE is simply
  "a context exists", the real meaning of these guards is P2's business.
- VertexInputStateFactory.h's comment stops naming pGLContext so purity gate C
  (grep -rc pGLContext MobileGL/MG_Backend/DirectVulkan) reads 0 in every file.
- The 12 SyncPersistentMappedRange and 3 SyncGpuWrites sites of the D10 table are
  untouched; PipeStats AddCalls literals unchanged.
- Proof on the pull build (Release/INFO, LTO off, vs feat/disaggregated@087685d1):
  symbol_report --threshold 0 -> 27799 symbols, 0 added / 0 removed / 0 resized /
  0 renamed, .text 10792579 -> 10792579 (+0); nm --defined-only name set identical;
  ctest -N name set identical (2334); unit 1466/1466; DirectVulkan integration lane
  427/427 on lavapipe (two ArmedWhenTheEnvironmentPinsItOn entries flake under -j 4
  exactly as on the baseline and pass serially). The push build compiles and links.
This commit is contained in:
2026-09-06 04:41:28 -04:00
parent d4504e30f8
commit bf8b39a867
8 changed files with 217 additions and 210 deletions
@@ -12,6 +12,7 @@
#include "SubgroupSupportPolicy.h" #include "SubgroupSupportPolicy.h"
#include "MG_State/GLState/FramebufferState/FramebufferObject.h" #include "MG_State/GLState/FramebufferState/FramebufferObject.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_State/GLState/TextureState/TextureState.h" #include "MG_State/GLState/TextureState/TextureState.h"
#include "MG_Util/Classifiers/TextureEnumClassifier.h" #include "MG_Util/Classifiers/TextureEnumClassifier.h"
#include "MG_Util/Converters/MGToGL/TextureEnumConverter.h" #include "MG_Util/Converters/MGToGL/TextureEnumConverter.h"
@@ -385,8 +386,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
UpdateDynamicBackendParameters(); UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions(); UpdateAdvertisedExtensions();
if (MG_State::pGLContext) { if (MGB_CTX_LIVE) {
MG_State::pGLContext->InvalidateCompileEnv(); MGB_CTX->InvalidateCompileEnv();
} }
PopulateFormatCapabilities(physicalDevice.handle, vkGetPhysicalDeviceFormatProperties, m_vulkanCaps, PopulateFormatCapabilities(physicalDevice.handle, vkGetPhysicalDeviceFormatProperties, m_vulkanCaps,
MutableFormatCapabilities()); MutableFormatCapabilities());
@@ -783,8 +784,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_vulkanCaps = capabilities; m_vulkanCaps = capabilities;
UpdateDynamicBackendParameters(); UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions(); UpdateAdvertisedExtensions();
if (MG_State::pGLContext) { if (MGB_CTX_LIVE) {
MG_State::pGLContext->InvalidateCompileEnv(); MGB_CTX->InvalidateCompileEnv();
} }
MutableFormatCapabilities().Clear(); MutableFormatCapabilities().Clear();
} }
@@ -10,6 +10,7 @@
#include "DirectVulkanResourceState.h" #include "DirectVulkanResourceState.h"
#include "MG_Backend/BackendObjects.h" #include "MG_Backend/BackendObjects.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_State/GLState/ErrorState/ErrorInfo.h" #include "MG_State/GLState/ErrorState/ErrorInfo.h"
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h" #include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
#include "MG_Util/Converters/GLToMG/TextureEnumConverter.h" #include "MG_Util/Converters/GLToMG/TextureEnumConverter.h"
@@ -267,15 +268,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
MG_State::GLState::ProgramObject* TryGetDirectVulkanProgram(GLuint program) { MG_State::GLState::ProgramObject* TryGetDirectVulkanProgram(GLuint program) {
if (!MG_State::pGLContext->ValidateProgramName(program)) { if (!MGB_CTX->ValidateProgramName(program)) {
return nullptr; return nullptr;
} }
auto& programObject = MG_State::pGLContext->GetProgramObject(program); auto& programObject = MGB_CTX->GetProgramObject(program);
return programObject.get(); return programObject.get();
} }
const Uint8* ResolveIndirectCommandBytes(const void* indirect, SizeT requiredBytes, const char* label) { const Uint8* ResolveIndirectCommandBytes(const void* indirect, SizeT requiredBytes, const char* label) {
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (drawBuffer) { if (drawBuffer) {
drawBuffer->SyncPersistentMappedRange(); drawBuffer->SyncPersistentMappedRange();
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect); const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
@@ -334,64 +335,64 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfi called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfi called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearBufferfi called with null GL context");
pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil); pVulkanRenderer->ClearBufferfi(buffer, drawbuffer, depth, stencil);
} }
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferfv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferfv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearBufferfv called with null GL context");
pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value); pVulkanRenderer->ClearBufferfv(buffer, drawbuffer, value);
} }
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferuiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferuiv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearBufferuiv called with null GL context");
pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value); pVulkanRenderer->ClearBufferuiv(buffer, drawbuffer, value);
} }
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearBufferiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearBufferiv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearBufferiv called with null GL context");
pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value); pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value);
} }
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLfloat* value) { GLint drawbuffer, const GLfloat* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearNamedFramebufferfv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value); pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
} }
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLint* value) { GLint drawbuffer, const GLint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferiv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferiv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearNamedFramebufferiv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value); pVulkanRenderer->ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value);
} }
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLuint* value) { GLint drawbuffer, const GLuint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferuiv called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferuiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferuiv called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearNamedFramebufferuiv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value); pVulkanRenderer->ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value);
} }
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil) { GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfi called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ClearNamedFramebufferfi called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil); pVulkanRenderer->ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
} }
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) { void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirect called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElementsIndirect called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride); pVulkanRenderer->MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
} }
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) { void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirect called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawArraysIndirect called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawArraysIndirect called with null GL context");
if (drawcount <= 0) { if (drawcount <= 0) {
return; return;
@@ -399,7 +400,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written // With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written
// (e.g. by a compute shader), so consume them natively on the GPU. // (e.g. by a compute shader), so consume them natively on the GPU.
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (drawBuffer) { if (drawBuffer) {
pVulkanRenderer->MultiDrawArraysIndirect(mode, indirect, drawcount, stride); pVulkanRenderer->MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
return; return;
@@ -442,13 +443,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) { GLsizei maxdrawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride); pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride);
} }
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount, void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) { GLsizei maxdrawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirectCount called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArraysIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawArraysIndirectCount called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawArraysIndirectCount called with null GL context");
if (maxdrawcount <= 0) { if (maxdrawcount <= 0) {
return; return;
@@ -462,7 +463,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return; return;
} }
auto parameterBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject(); auto parameterBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
if (!parameterBuffer || drawcount < 0 || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterBuffer->GetSize()) { if (!parameterBuffer || drawcount < 0 || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterBuffer->GetSize()) {
MGLOG_E_ONCE("MultiDrawArraysIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range"); MGLOG_E_ONCE("MultiDrawArraysIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range");
return; return;
@@ -493,7 +494,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices,
GLsizei instancecount, GLint basevertex, GLuint baseinstance) { GLsizei instancecount, GLint basevertex, GLuint baseinstance) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawElementsInstancedBaseVertexBaseInstance called with null GL context");
DrawIndexedCmd payload{}; DrawIndexedCmd payload{};
payload.mode = mode; payload.mode = mode;
@@ -520,7 +521,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) { void DrawElementsIndirect(GLenum mode, GLenum type, const void* indirect) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsIndirect called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsIndirect called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawElementsIndirect called with null GL context");
const SizeT indexSize = MG_Util::GetGLTypeSize(type); const SizeT indexSize = MG_Util::GetGLTypeSize(type);
if (indexSize == 0) { if (indexSize == 0) {
@@ -530,7 +531,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written // With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written
// (e.g. by a compute shader), so consume them natively on the GPU. // (e.g. by a compute shader), so consume them natively on the GPU.
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (drawBuffer) { if (drawBuffer) {
pVulkanRenderer->MultiDrawElementsIndirect(mode, type, indirect, 1, 0); pVulkanRenderer->MultiDrawElementsIndirect(mode, type, indirect, 1, 0);
return; return;
@@ -564,7 +565,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, void DrawArraysInstancedBaseInstance(GLenum mode, GLint first, GLsizei count, GLsizei instancecount,
GLuint baseinstance) { GLuint baseinstance) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysInstancedBaseInstance called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysInstancedBaseInstance called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArraysInstancedBaseInstance called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawArraysInstancedBaseInstance called with null GL context");
DrawCmd payload{}; DrawCmd payload{};
payload.mode = mode; payload.mode = mode;
@@ -579,11 +580,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void DrawArraysIndirect(GLenum mode, const void* indirect) { void DrawArraysIndirect(GLenum mode, const void* indirect) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysIndirect called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArraysIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArraysIndirect called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawArraysIndirect called with null GL context");
// With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written // With a bound GL_DRAW_INDIRECT_BUFFER the command parameters may be GPU-written
// (e.g. by a compute shader), so consume them natively on the GPU. // (e.g. by a compute shader), so consume them natively on the GPU.
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (drawBuffer) { if (drawBuffer) {
pVulkanRenderer->MultiDrawArraysIndirect(mode, indirect, 1, 0); pVulkanRenderer->MultiDrawArraysIndirect(mode, indirect, 1, 0);
return; return;
@@ -613,13 +614,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border) { GLsizei height, GLint border) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexImage2D called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexImage2D called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::CopyTexImage2D called with null GL context");
pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height); pVulkanRenderer->CopyTexSubImage2D(target, level, 0, 0, x, y, width, height);
} }
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width,
GLsizei height) { GLsizei height) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyTexSubImage2D called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyTexSubImage2D called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::CopyTexSubImage2D called with null GL context");
pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); pVulkanRenderer->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
} }
void CopyImageSubData(const CopyImageEndpoint& src, void CopyImageSubData(const CopyImageEndpoint& src,
@@ -628,32 +629,32 @@ namespace MobileGL::MG_Backend::DirectVulkan {
GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ,
GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyImageSubData called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::CopyImageSubData called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::CopyImageSubData called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::CopyImageSubData called with null GL context");
pVulkanRenderer->CopyImageSubData(src, srcTarget, srcLevel, srcX, srcY, srcZ, pVulkanRenderer->CopyImageSubData(src, srcTarget, srcLevel, srcX, srcY, srcZ,
dst, dstTarget, dstLevel, dstX, dstY, dstZ, dst, dstTarget, dstLevel, dstX, dstY, dstZ,
srcWidth, srcHeight, srcDepth); srcWidth, srcHeight, srcDepth);
} }
void GenerateMipmap(GLenum target) { void GenerateMipmap(GLenum target) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GenerateMipmap called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GenerateMipmap called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GenerateMipmap called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::GenerateMipmap called with null GL context");
pVulkanRenderer->GenerateMipmap(target); pVulkanRenderer->GenerateMipmap(target);
} }
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) { void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchCompute called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchCompute called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchCompute called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DispatchCompute called with null GL context");
pVulkanRenderer->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ); pVulkanRenderer->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
} }
void DispatchComputeIndirect(GLintptr indirect) { void DispatchComputeIndirect(GLintptr indirect) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchComputeIndirect called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DispatchComputeIndirect called with null GL context");
pVulkanRenderer->DispatchComputeIndirect(indirect); pVulkanRenderer->DispatchComputeIndirect(indirect);
} }
void MemoryBarrier(GLbitfield barriers) { void MemoryBarrier(GLbitfield barriers) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MemoryBarrier called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MemoryBarrier called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MemoryBarrier called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MemoryBarrier called with null GL context");
pVulkanRenderer->MemoryBarrier(barriers); pVulkanRenderer->MemoryBarrier(barriers);
} }
@@ -713,7 +714,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
? pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBufferBindings ? pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBufferBindings
: 0; : 0;
if (storageBlockBinding >= static_cast<GLuint>(maxBindings)) { if (storageBlockBinding >= static_cast<GLuint>(maxBindings)) {
MG_State::pGLContext->RecordError( MGB_CTX->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("DirectVulkan", __func__, "Shader storage binding is out of range.")); MakeUnique<GenericErrorInfo>("DirectVulkan", __func__, "Shader storage binding is out of range."));
return; return;
@@ -738,24 +739,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) { void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ReadPixels called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::ReadPixels called with null GL context");
pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels); pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels);
} }
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) { void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTexImage called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTexImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTexImage called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::GetTexImage called with null GL context");
pVulkanRenderer->GetTexImage(target, level, format, type, pixels); pVulkanRenderer->GetTexImage(target, level, format, type, pixels);
} }
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget, void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels) { GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTextureImage called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTextureImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTextureImage called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::GetTextureImage called with null GL context");
pVulkanRenderer->GetTextureImage(texture, uploadTarget, level, format, type, bufSize, pixels); pVulkanRenderer->GetTextureImage(texture, uploadTarget, level, format, type, bufSize, pixels);
} }
void Clear(GLbitfield mask) { void Clear(GLbitfield mask) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Clear called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::Clear called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::Clear called with null GL context");
pVulkanRenderer->Clear(mask); pVulkanRenderer->Clear(mask);
} }
@@ -783,7 +784,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
const Uint8* indexBytes = nullptr; const Uint8* indexBytes = nullptr;
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
const auto& indexBufferShared = vao.GetIndexBufferBindingSlot().GetBoundObject(); const auto& indexBufferShared = vao.GetIndexBufferBindingSlot().GetBoundObject();
if (indexBufferShared != nullptr) { if (indexBufferShared != nullptr) {
const SizeT offset = reinterpret_cast<SizeT>(indices); const SizeT offset = reinterpret_cast<SizeT>(indices);
@@ -814,7 +815,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawArrays(GLenum mode, GLint first, GLsizei count) { void DrawArrays(GLenum mode, GLint first, GLsizei count) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawArrays called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawArrays called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawArrays called with null GL context");
if (mode == GL_LINE_LOOP) { if (mode == GL_LINE_LOOP) {
if (count < 2) { if (count < 2) {
@@ -839,7 +840,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElements called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawElements called with null GL context");
if (mode == GL_LINE_LOOP) { if (mode == GL_LINE_LOOP) {
Vector<Uint32> closedIndices; Vector<Uint32> closedIndices;
@@ -862,7 +863,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) { void MultiDrawArrays(GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArrays called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawArrays called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawArrays called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawArrays called with null GL context");
if (drawcount <= 0) { if (drawcount <= 0) {
return; return;
} }
@@ -907,7 +908,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// MultiDrawIndexedCmd left the client-memory shape addressing a view whose byte // MultiDrawIndexedCmd left the client-memory shape addressing a view whose byte
// offset is a hardcoded 0, so UploadAndBindIndexBuffer saw a null client pointer, // offset is a hardcoded 0, so UploadAndBindIndexBuffer saw a null client pointer,
// declined the whole batch and painted nothing.) // declined the whole batch and painted nothing.)
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
if (vao.GetIndexBufferBindingSlot().GetBoundObject() == nullptr) { if (vao.GetIndexBufferBindingSlot().GetBoundObject() == nullptr) {
for (GLsizei i = 0; i < drawcount; ++i) { for (GLsizei i = 0; i < drawcount; ++i) {
if (count[i] <= 0) { if (count[i] <= 0) {
@@ -968,13 +969,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, void MultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount) { GLsizei drawcount) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElements called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElements called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElements called with null GL context");
MultiDrawElementsImpl(mode, count, type, indices, drawcount, nullptr); MultiDrawElementsImpl(mode, count, type, indices, drawcount, nullptr);
} }
void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) { void DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLint basevertex) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DrawElementsBaseVertex called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::DrawElementsBaseVertex called with null GL context");
if (mode == GL_LINE_LOOP) { if (mode == GL_LINE_LOOP) {
Vector<Uint32> closedIndices; Vector<Uint32> closedIndices;
if (BuildClosedLineLoopIndices(count, type, indices, closedIndices)) { if (BuildClosedLineLoopIndices(count, type, indices, closedIndices)) {
@@ -998,14 +999,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices, void MultiDrawElementsBaseVertex(GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const* indices,
GLsizei drawcount, const GLint* basevertex) { GLsizei drawcount, const GLint* basevertex) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsBaseVertex called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::MultiDrawElementsBaseVertex called with null GL context");
MultiDrawElementsImpl(mode, count, type, indices, drawcount, basevertex); MultiDrawElementsImpl(mode, count, type, indices, drawcount, basevertex);
} }
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter) { GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitFramebuffer called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::BlitFramebuffer called with null GL context"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "DirectVulkan::BlitFramebuffer called with null GL context");
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
} }
@@ -1233,8 +1234,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
if (query->kind == VulkanTimerQuery::Kind::XfbGenerated && if (query->kind == VulkanTimerQuery::Kind::XfbGenerated &&
!query->pausedPrimitivesCountedByGpu && MG_State::pGLContext != nullptr) { !query->pausedPrimitivesCountedByGpu && MGB_CTX_LIVE) {
primitives += MG_State::pGLContext->GetTransformFeedbackPausedPrimitiveCounter() - primitives += MGB_CTX->GetTransformFeedbackPausedPrimitiveCounter() -
query->pausedPrimitiveSnapshot; query->pausedPrimitiveSnapshot;
} }
*outNanoseconds = primitives; *outNanoseconds = primitives;
@@ -1281,7 +1282,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
query->kind = generated ? VulkanTimerQuery::Kind::XfbGenerated : VulkanTimerQuery::Kind::XfbWritten; query->kind = generated ? VulkanTimerQuery::Kind::XfbGenerated : VulkanTimerQuery::Kind::XfbWritten;
query->rendererGeneration = GetRendererGeneration(); query->rendererGeneration = GetRendererGeneration();
query->pausedPrimitiveSnapshot = query->pausedPrimitiveSnapshot =
MG_State::pGLContext ? MG_State::pGLContext->GetTransformFeedbackPausedPrimitiveCounter() : 0; MGB_CTX_LIVE ? MGB_CTX->GetTransformFeedbackPausedPrimitiveCounter() : 0;
// Read AFTER StartXfbQueryCapture, which is where a failed reroute-pool creation // Read AFTER StartXfbQueryCapture, which is where a failed reroute-pool creation
// disarms: the answer is then what this span will actually do for every draw. // disarms: the answer is then what this span will actually do for every draw.
query->pausedPrimitivesCountedByGpu = generated && pVulkanRenderer->ArePausedDrawsGpuCounted(); query->pausedPrimitivesCountedByGpu = generated && pVulkanRenderer->ArePausedDrawsGpuCounted();
@@ -10,6 +10,7 @@
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h" #include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_State/GLState/ProgramState/ProgramObject.h" #include "MG_State/GLState/ProgramState/ProgramObject.h"
#include "MG_State/GLState/TextureState/TextureObject1D.h" #include "MG_State/GLState/TextureState/TextureObject1D.h"
#include "MG_State/GLState/TextureState/TextureObject2D.h" #include "MG_State/GLState/TextureState/TextureObject2D.h"
@@ -503,7 +504,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// alive through the draw via GL binding state. Only the fallback path needs a SharedPtr to // alive through the draw via GL binding state. Only the fallback path needs a SharedPtr to
// keep the fallback texture alive for the rest of this call. // keep the fallback texture alive for the rest of this call.
MG_State::GLState::ITextureObject* texture = ResolveSamplerTextureRaw(program, programObj, binding, element); MG_State::GLState::ITextureObject* texture = ResolveSamplerTextureRaw(program, programObj, binding, element);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
const auto& samplerOverride = textureUnit.GetSamplerObject(); const auto& samplerOverride = textureUnit.GetSamplerObject();
const auto preferredTarget = programObj.samplerTextureTargetByBinding[binding]; const auto preferredTarget = programObj.samplerTextureTargetByBinding[binding];
SharedPtr<MG_State::GLState::ITextureObject> fallbackHolder; SharedPtr<MG_State::GLState::ITextureObject> fallbackHolder;
@@ -552,7 +553,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
if (!IsValidSampledImageLayout(resource->layout)) { if (!IsValidSampledImageLayout(resource->layout)) {
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); auto drawFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None; FramebufferAttachmentType attachmentType = FramebufferAttachmentType::None;
Int attachmentLevel = 0; Int attachmentLevel = 0;
if (drawFbo && if (drawFbo &&
@@ -779,7 +780,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// filtering - which a single-level view can still have. Resolve the sampler exactly // filtering - which a single-level view can still have. Resolve the sampler exactly
// the way ResolveSamplerDescriptor does and bail if anisotropy would apply. // the way ResolveSamplerDescriptor does and bail if anisotropy would apply.
const Int unit = ResolveSamplerUnitIndex(program, location, binding); const Int unit = ResolveSamplerUnitIndex(program, location, binding);
const auto& samplerOverride = MG_State::pGLContext->GetTextureUnitObject(unit).GetSamplerObject(); const auto& samplerOverride = MGB_CTX->GetTextureUnitObject(unit).GetSamplerObject();
const auto* effectiveSampler = const auto* effectiveSampler =
samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get(); samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
if (effectiveSampler == nullptr) return false; if (effectiveSampler == nullptr) return false;
@@ -809,7 +810,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const ProgramFactory::VkProgramObject& programObj, Uint32 binding, const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) { SharedPtr<MG_State::GLState::ITextureObject>& outTexture) {
outTexture.reset(); outTexture.reset();
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveSamplerTexture: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveSamplerTexture: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveSamplerTexture: sampler location binding %u out of range", binding); "ResolveSamplerTexture: sampler location binding %u out of range", binding);
MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(),
@@ -818,7 +819,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const Int location = programObj.samplerUniformLocationByBinding[binding]; const Int location = programObj.samplerUniformLocationByBinding[binding];
const Int unit = ResolveSamplerUnitIndex(program, location, binding); const Int unit = ResolveSamplerUnitIndex(program, location, binding);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding]; const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject(); outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
// The slot always holds at least the target's default texture (name 0). While that // The slot always holds at least the target's default texture (name 0). While that
@@ -834,7 +835,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MG_State::GLState::ITextureObject* UniformManager::ResolveSamplerTextureRaw( MG_State::GLState::ITextureObject* UniformManager::ResolveSamplerTextureRaw(
const MG_State::GLState::ProgramObject& program, const ProgramFactory::VkProgramObject& programObj, const MG_State::GLState::ProgramObject& program, const ProgramFactory::VkProgramObject& programObj,
Uint32 binding, Uint32 element) { Uint32 binding, Uint32 element) {
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveSamplerTextureRaw: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveSamplerTextureRaw: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveSamplerTextureRaw: sampler location binding %u out of range", binding); "ResolveSamplerTextureRaw: sampler location binding %u out of range", binding);
MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(),
@@ -844,7 +845,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
ResolveDescriptorElementLocation(program, programObj.samplerUniformLocationByBinding[binding], element); ResolveDescriptorElementLocation(program, programObj.samplerUniformLocationByBinding[binding], element);
const Int unit = ResolveSamplerUnitIndex(program, location, binding); const Int unit = ResolveSamplerUnitIndex(program, location, binding);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding]; const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
// GetBoundObject() returns the SharedPtr by const ref; .get() reads the pointer without // GetBoundObject() returns the SharedPtr by const ref; .get() reads the pointer without
// touching the refcount (no atomic inc/dec per binding per draw). // touching the refcount (no atomic inc/dec per binding per draw).
@@ -989,7 +990,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkBufferView& outBufferView) { VkBufferView& outBufferView) {
outBufferView = VK_NULL_HANDLE; outBufferView = VK_NULL_HANDLE;
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageTexelBufferDescriptor: buffer manager is null"); MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageTexelBufferDescriptor: buffer manager is null");
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageTexelBufferDescriptor: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveStorageTexelBufferDescriptor: GL context is null");
MOBILEGL_ASSERT(frameIndex < m_frames.size(), MOBILEGL_ASSERT(frameIndex < m_frames.size(),
"ResolveStorageTexelBufferDescriptor: frame index out of range"); "ResolveStorageTexelBufferDescriptor: frame index out of range");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
@@ -1013,7 +1014,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(binding < programObj.samplerNumericDomainByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerNumericDomainByBinding.size(),
"ResolveStorageTexelBufferDescriptor: numeric domain binding %u out of range", binding); "ResolveStorageTexelBufferDescriptor: numeric domain binding %u out of range", binding);
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(imageUnit); auto& imageBinding = MGB_CTX->GetImageTextureBinding(imageUnit);
const auto& texture = imageBinding.Texture; const auto& texture = imageBinding.Texture;
if (texture == nullptr) { if (texture == nullptr) {
// An image unit with no texture on it is legal GL (4.6 core 8.26): loads return zero // An image unit with no texture on it is legal GL (4.6 core 8.26): loads return zero
@@ -1149,7 +1150,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkDescriptorBufferInfo& outBufferInfo) const { VkDescriptorBufferInfo& outBufferInfo) const {
outBufferInfo = {}; outBufferInfo = {};
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null"); MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null");
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageBufferDescriptor: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveStorageBufferDescriptor: GL context is null");
MOBILEGL_ASSERT(binding < programObj.storageBlockIndexByBinding.size(), MOBILEGL_ASSERT(binding < programObj.storageBlockIndexByBinding.size(),
"ResolveStorageBufferDescriptor: binding %u out of range", binding); "ResolveStorageBufferDescriptor: binding %u out of range", binding);
@@ -1186,12 +1187,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
? static_cast<GLuint>(atomicCounterBinding) ? static_cast<GLuint>(atomicCounterBinding)
: GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex)) + element; : GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex)) + element;
const Uint32 bindingPointCount = const Uint32 bindingPointCount =
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(bufferTarget)); static_cast<Uint32>(MGB_CTX->GetBufferBindingPointCount(bufferTarget));
MOBILEGL_ASSERT(frontendBinding < bindingPointCount, MOBILEGL_ASSERT(frontendBinding < bindingPointCount,
"ResolveStorageBufferDescriptor: frontend binding %u out of range for block '%s'", "ResolveStorageBufferDescriptor: frontend binding %u out of range for block '%s'",
frontendBinding, blockName.c_str()); frontendBinding, blockName.c_str());
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, frontendBinding); auto& bindingPoint = MGB_CTX->GetBufferBindingPoint(bufferTarget, frontendBinding);
const auto& bufferObject = bindingPoint.GetBoundObject(); const auto& bufferObject = bindingPoint.GetBoundObject();
if (bufferObject == nullptr) { if (bufferObject == nullptr) {
// NOT an error, and above all not a reason to lose the draw. GL 4.6 core 7.8 lets a // NOT an error, and above all not a reason to lose the draw. GL 4.6 core 7.8 lets a
@@ -1263,7 +1264,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkDescriptorImageInfo& outImageInfo) const { VkDescriptorImageInfo& outImageInfo) const {
outImageInfo = {}; outImageInfo = {};
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveStorageImageDescriptor: texture manager is null"); MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveStorageImageDescriptor: texture manager is null");
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveStorageImageDescriptor: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveStorageImageDescriptor: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveStorageImageDescriptor: binding %u out of range", binding); "ResolveStorageImageDescriptor: binding %u out of range", binding);
@@ -1292,7 +1293,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
auto& imageBinding = MG_State::pGLContext->GetImageTextureBinding(imageUnit); auto& imageBinding = MGB_CTX->GetImageTextureBinding(imageUnit);
if (imageBinding.Texture == nullptr) { if (imageBinding.Texture == nullptr) {
// Legal GL: an image unit with no texture bound makes loads return zero and discards // Legal GL: an image unit with no texture bound makes loads return zero and discards
// stores (4.6 core 8.26). It is not a reason to lose the draw, which is what returning // stores (4.6 core 8.26). It is not a reason to lose the draw, which is what returning
@@ -1648,7 +1649,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// Open-coded ResolveSamplerTextureRaw so the unit is resolved once for both the // Open-coded ResolveSamplerTextureRaw so the unit is resolved once for both the
// texture and the sampler override - this runs per binding per full-path draw, // texture and the sampler override - this runs per binding per full-path draw,
// and program-alternating draw streams take the full path on every draw. // and program-alternating draw streams take the full path on every draw.
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveSampledBinding: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveSampledBinding: GL context is null");
MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerUniformLocationByBinding.size(),
"ResolveSampledBinding: sampler location binding %u out of range", binding); "ResolveSampledBinding: sampler location binding %u out of range", binding);
MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerTextureTargetByBinding.size(),
@@ -1659,7 +1660,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
const Int unit = ResolveSamplerUnitIndex(program, location, binding); const Int unit = ResolveSamplerUnitIndex(program, location, binding);
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit); auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit);
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding]; const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
MG_State::GLState::ITextureObject* texture = MG_State::GLState::ITextureObject* texture =
textureUnit.GetBindingSlot(preferredTarget).GetBoundObject().get(); textureUnit.GetBindingSlot(preferredTarget).GetBoundObject().get();
@@ -1803,7 +1804,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const ProgramFactory::VkProgramObject& programObj, const ProgramFactory::VkProgramObject& programObj,
Vector<MG_State::GLState::ITextureObject*>& outTextures) const { Vector<MG_State::GLState::ITextureObject*>& outTextures) const {
outTextures.clear(); outTextures.clear();
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, MOBILEGL_ASSERT(MGB_CTX_LIVE,
"CollectStorageImageTextures: GL context is null"); "CollectStorageImageTextures: GL context is null");
// Same as the sampled walk: a declined program is refused at bind time, and its declined // Same as the sampled walk: a declined program is refused at bind time, and its declined
// binding has no uniform location to reach an image unit through. // binding has no uniform location to reach an image unit through.
@@ -1847,7 +1848,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
auto* texture = MG_State::pGLContext->GetImageTextureBinding(imageUnit).Texture.get(); auto* texture = MGB_CTX->GetImageTextureBinding(imageUnit).Texture.get();
if (texture == nullptr) { if (texture == nullptr) {
// ResolveStorageImageDescriptor will substitute the placeholder image for this // ResolveStorageImageDescriptor will substitute the placeholder image for this
// binding; include it here for the same reason the sampled walk includes the // binding; include it here for the same reason the sampled walk includes the
@@ -1885,7 +1886,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const ProgramFactory::VkProgramObject& programObj, const ProgramFactory::VkProgramObject& programObj,
Vector<SamplerImageFeedbackBinding>& outBindings) const { Vector<SamplerImageFeedbackBinding>& outBindings) const {
outBindings.clear(); outBindings.clear();
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, MOBILEGL_ASSERT(MGB_CTX_LIVE,
"CollectSamplerImageFeedback: GL context is null"); "CollectSamplerImageFeedback: GL context is null");
if (programObj.declinedDescriptors) return true; if (programObj.declinedDescriptors) return true;
@@ -1935,7 +1936,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (imageUnit < 0 || imageUnit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) { if (imageUnit < 0 || imageUnit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
return false; return false;
} }
const auto& image = MG_State::pGLContext->GetImageTextureBinding(imageUnit); const auto& image = MGB_CTX->GetImageTextureBinding(imageUnit);
// A sampler view exposes all layers of its target; equal texture plus an // A sampler view exposes all layers of its target; equal texture plus an
// overlapping mip therefore aliases the writable image subresource. // overlapping mip therefore aliases the writable image subresource.
if (image.Texture.get() == sampledTexture && if (image.Texture.get() == sampledTexture &&
@@ -1965,7 +1966,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const void* outData = nullptr; const void* outData = nullptr;
VkDeviceSize outSize = 0; VkDeviceSize outSize = 0;
MOBILEGL_ASSERT(MG_State::pGLContext != nullptr, "ResolveUniformBufferPayload: GL context is null"); MOBILEGL_ASSERT(MGB_CTX_LIVE, "ResolveUniformBufferPayload: GL context is null");
MOBILEGL_ASSERT(binding < programObj.bindingKinds.size(), MOBILEGL_ASSERT(binding < programObj.bindingKinds.size(),
"ResolveUniformBufferPayload: binding %u out of range", binding); "ResolveUniformBufferPayload: binding %u out of range", binding);
MOBILEGL_ASSERT(programObj.bindingKinds[binding] == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic, MOBILEGL_ASSERT(programObj.bindingKinds[binding] == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic,
@@ -2010,12 +2011,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const Uint32 frontendBinding = program.GetUniformBlockBinding(static_cast<Uint32>(blockIndex)); const Uint32 frontendBinding = program.GetUniformBlockBinding(static_cast<Uint32>(blockIndex));
const Uint32 uniformBindingPointCount = const Uint32 uniformBindingPointCount =
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::Uniform)); static_cast<Uint32>(MGB_CTX->GetBufferBindingPointCount(BufferTarget::Uniform));
MOBILEGL_ASSERT(frontendBinding < uniformBindingPointCount, MOBILEGL_ASSERT(frontendBinding < uniformBindingPointCount,
"ResolveUniformBufferPayload: frontend UBO binding %u out of range for block '%s'", "ResolveUniformBufferPayload: frontend UBO binding %u out of range for block '%s'",
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str()); frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
auto& bindingPoint = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::Uniform, frontendBinding); auto& bindingPoint = MGB_CTX->GetBufferBindingPoint(BufferTarget::Uniform, frontendBinding);
const auto& bufferObject = bindingPoint.GetBoundObject(); const auto& bufferObject = bindingPoint.GetBoundObject();
MOBILEGL_ASSERT(bufferObject != nullptr, MOBILEGL_ASSERT(bufferObject != nullptr,
"ResolveUniformBufferPayload: no UBO bound at frontend binding %u for block '%s'", "ResolveUniformBufferPayload: no UBO bound at frontend binding %u for block '%s'",
@@ -130,7 +130,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// stale memo. // stale memo.
// //
// Drawn from a process-wide source, never a per-instance counter: the VAO // Drawn from a process-wide source, never a per-instance counter: the VAO
// memos outlive this factory (they live on pGLContext's VAOs, the renderer // memos outlive this factory (they live on the frontend context's VAOs, the renderer
// is destroyed and recreated on EGL surface release/re-create), so a fresh // is destroyed and recreated on EGL surface release/re-create), so a fresh
// factory restarting at a dead factory's epoch value would honor its // factory restarting at a dead factory's epoch value would honor its
// dangling entry pointers. The constructor takes a value strictly greater // dangling entry pointers. The constructor takes a value strictly greater
@@ -13,6 +13,7 @@
#include "VkTextureManager.h" #include "VkTextureManager.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h" #include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h" #include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
@@ -54,7 +55,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (payload.colorEncoding != ClearColorEncoding::Float) return; if (payload.colorEncoding != ClearColorEncoding::Float) return;
// With GL_FRAMEBUFFER_SRGB enabled GL performs the encoding itself, so the driver doing it // With GL_FRAMEBUFFER_SRGB enabled GL performs the encoding itself, so the driver doing it
// is exactly right and there is nothing to undo. // is exactly right and there is nothing to undo.
if (MG_State::pGLContext->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)) return; if (MGB_CTX->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 colour channels only: alpha is stored
@@ -13,6 +13,7 @@
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h" #include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h" #include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
#include "MG_Util/Metrics/TextureMetrics.h" #include "MG_Util/Metrics/TextureMetrics.h"
#include <MG_Pipe/PipeInputsSwitch.h>
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
static Bool TryResolveSampleCountFlagBits(Int requestedSamples, VkSampleCountFlagBits& outSampleCount) { static Bool TryResolveSampleCountFlagBits(Int requestedSamples, VkSampleCountFlagBits& outSampleCount) {
@@ -610,7 +611,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// sRGB attachments switch between their sRGB and UNORM-twin views with this // sRGB attachments switch between their sRGB and UNORM-twin views with this
// capability (ResolveSrgbAttachmentWriteFormat), changing the render pass formats. // capability (ResolveSrgbAttachmentWriteFormat), changing the render pass formats.
const Bool framebufferSrgbEnabled = const Bool framebufferSrgbEnabled =
MG_State::pGLContext->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb); MGB_CTX->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb);
XXHASH_VERIFY(XXH64_update(m_hashState, &framebufferSrgbEnabled, sizeof(framebufferSrgbEnabled))); XXHASH_VERIFY(XXH64_update(m_hashState, &framebufferSrgbEnabled, sizeof(framebufferSrgbEnabled)));
auto& drawBuffers = fbo.GetDrawBuffers(); auto& drawBuffers = fbo.GetDrawBuffers();
XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0]))); XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0])));
@@ -962,7 +963,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const VkImageLayout trackedRbLayout = rbResource->layout; const VkImageLayout trackedRbLayout = rbResource->layout;
const Bool rbFramebufferSrgb = const Bool rbFramebufferSrgb =
MG_State::pGLContext->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb); MGB_CTX->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb);
const VkFormat rbAttachmentFormat = const VkFormat rbAttachmentFormat =
ResolveSrgbAttachmentWriteFormat(rbResource->format, rbFramebufferSrgb); ResolveSrgbAttachmentWriteFormat(rbResource->format, rbFramebufferSrgb);
rbDesc.flags = 0; rbDesc.flags = 0;
@@ -1108,7 +1109,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
textureResources.emplace_back(textureResource); textureResources.emplace_back(textureResource);
desc.format = ResolveSrgbAttachmentWriteFormat( desc.format = ResolveSrgbAttachmentWriteFormat(
textureResource->format, textureResource->format,
MG_State::pGLContext->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb)); MGB_CTX->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb));
attachmentSampleCount = textureResource->sampleCount; attachmentSampleCount = textureResource->sampleCount;
trackedColorLayout = textureResource->layout; trackedColorLayout = textureResource->layout;
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo { trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
@@ -11,6 +11,7 @@
#include "ProgramFactory.h" #include "ProgramFactory.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_Util/Converters/MGToStr/TextureEnumConverter.h" #include "MG_Util/Converters/MGToStr/TextureEnumConverter.h"
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h" #include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
#include "MG_Util/Metrics/PipeStats.h" #include "MG_Util/Metrics/PipeStats.h"
@@ -806,7 +807,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// sampled-texture sync scan the entire alive-texture map per draw. // sampled-texture sync scan the entire alive-texture map per draw.
if (aliveIt == m_aliveObjects.end()) { if (aliveIt == m_aliveObjects.end()) {
WeakPtr<MG_State::GLState::ITextureObject> aliveTexture; WeakPtr<MG_State::GLState::ITextureObject> aliveTexture;
const auto& liveTexture = MG_State::pGLContext->GetTextureObject(texture.GetExternalIndex()); const auto& liveTexture = MGB_CTX->GetTextureObject(texture.GetExternalIndex());
if (liveTexture && liveTexture.get() == &texture) { if (liveTexture && liveTexture.get() == &texture) {
aliveTexture = liveTexture; aliveTexture = liveTexture;
} else { } else {
@@ -949,7 +950,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
const Bool framebufferSrgbEnabled = const Bool framebufferSrgbEnabled =
MG_State::pGLContext->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb); MGB_CTX->IsCapabilityEnabled(MobileGL::CapabilityInput::FramebufferSrgb);
const VkFormat baseAttachmentFormat = const VkFormat baseAttachmentFormat =
viewFormatOverride != VK_FORMAT_UNDEFINED ? viewFormatOverride : resource->format; viewFormatOverride != VK_FORMAT_UNDEFINED ? viewFormatOverride : resource->format;
const VkFormat attachmentFormat = const VkFormat attachmentFormat =
@@ -14,6 +14,7 @@
#include "VertexInputStateBuilder.h" #include "VertexInputStateBuilder.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include <MG_Pipe/PipeInputsSwitch.h>
#include "MG_State/GLState/ProgramState/ProgramObject.h" #include "MG_State/GLState/ProgramState/ProgramObject.h"
#include "MG_State/GLState/ProgramState/ShaderObject.h" #include "MG_State/GLState/ProgramState/ShaderObject.h"
#include "MG_State/GLState/SamplerState/SamplerObject.h" #include "MG_State/GLState/SamplerState/SamplerObject.h"
@@ -460,12 +461,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// round trip), which is why the honest-but-lossy path was kept over widening every // round trip), which is why the honest-but-lossy path was kept over widening every
// default-framebuffer Y-flip/pre-transform helper to floats. See the KNOWN INFIDELITY // default-framebuffer Y-flip/pre-transform helper to floats. See the KNOWN INFIDELITY
// note in MG_IntegrationTest/Scenarios/AdvertisedLimitsScenario.cpp. // note in MG_IntegrationTest/Scenarios/AdvertisedLimitsScenario.cpp.
const FloatVec4& stored = MG_State::pGLContext->GetViewportIndexed(index); const FloatVec4& stored = MGB_CTX->GetViewportIndexed(index);
const IntVec4 viewportState(static_cast<Int>(std::lround(stored.x())), const IntVec4 viewportState(static_cast<Int>(std::lround(stored.x())),
static_cast<Int>(std::lround(stored.y())), static_cast<Int>(std::lround(stored.y())),
static_cast<Int>(std::lround(stored.z())), static_cast<Int>(std::lround(stored.z())),
static_cast<Int>(std::lround(stored.w()))); static_cast<Int>(std::lround(stored.w())));
const FloatVec2& depthRange = MG_State::pGLContext->GetDepthRangeIndexed(index); const FloatVec2& depthRange = MGB_CTX->GetDepthRangeIndexed(index);
const IntVec2 logicalExtent = isDefaultFramebuffer const IntVec2 logicalExtent = isDefaultFramebuffer
? ResolveDefaultFramebufferLogicalExtent(preTransform, framebufferExtent) ? ResolveDefaultFramebufferLogicalExtent(preTransform, framebufferExtent)
: framebufferExtent; : framebufferExtent;
@@ -520,7 +521,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void ApplyBlendConstants(VkCommandBuffer commandBuffer) { static void ApplyBlendConstants(VkCommandBuffer commandBuffer) {
const FloatVec4& blendColor = MG_State::pGLContext->GetBlendColor(); const FloatVec4& blendColor = MGB_CTX->GetBlendColor();
const float blendConstants[4] = { const float blendConstants[4] = {
blendColor.x(), blendColor.x(),
blendColor.y(), blendColor.y(),
@@ -553,8 +554,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void ApplyPolygonOffsetState(VkCommandBuffer commandBuffer) { static void ApplyPolygonOffsetState(VkCommandBuffer commandBuffer) {
const Float constantFactor = MG_State::pGLContext->GetPolygonOffsetUnits(); const Float constantFactor = MGB_CTX->GetPolygonOffsetUnits();
const Float slopeFactor = MG_State::pGLContext->GetPolygonOffsetFactor(); const Float slopeFactor = MGB_CTX->GetPolygonOffsetFactor();
auto& shadow = g_dynamicStateShadow; auto& shadow = g_dynamicStateShadow;
if (shadow.depthBiasValid && shadow.depthBiasConstantFactor == constantFactor && if (shadow.depthBiasValid && shadow.depthBiasConstantFactor == constantFactor &&
shadow.depthBiasSlopeFactor == slopeFactor) { shadow.depthBiasSlopeFactor == slopeFactor) {
@@ -567,7 +568,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void ApplyLineWidthState(VkCommandBuffer commandBuffer) { static void ApplyLineWidthState(VkCommandBuffer commandBuffer) {
Float lineWidth = MG_State::pGLContext->GetLineWidth(); Float lineWidth = MGB_CTX->GetLineWidth();
if (MG_Backend::pActiveBackendObject != nullptr) { if (MG_Backend::pActiveBackendObject != nullptr) {
const auto& dynamicParameters = MG_Backend::pActiveBackendObject->GetDynamicParameters(); const auto& dynamicParameters = MG_Backend::pActiveBackendObject->GetDynamicParameters();
const Float minLineWidth = dynamicParameters.AliasedLineWidthRangeMin; const Float minLineWidth = dynamicParameters.AliasedLineWidthRangeMin;
@@ -646,8 +647,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void ApplyStencilState(VkCommandBuffer commandBuffer) { static void ApplyStencilState(VkCommandBuffer commandBuffer) {
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front); const StencilFaceState& frontStencil = MGB_CTX->GetStencilState(StencilFace::Front);
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back); const StencilFaceState& backStencil = MGB_CTX->GetStencilState(StencilFace::Back);
const Uint32 frontReference = static_cast<Uint32>(std::max(frontStencil.Ref, 0)); const Uint32 frontReference = static_cast<Uint32>(std::max(frontStencil.Ref, 0));
const Uint32 backReference = static_cast<Uint32>(std::max(backStencil.Ref, 0)); const Uint32 backReference = static_cast<Uint32>(std::max(backStencil.Ref, 0));
@@ -1240,11 +1241,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void RecordClearBufferError(const char* func, ErrorCode code, const char* message) { static void RecordClearBufferError(const char* func, ErrorCode code, const char* message) {
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message)); MGB_CTX->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
} }
static void RecordTextureCopyError(const char* func, ErrorCode code, const char* message) { static void RecordTextureCopyError(const char* func, ErrorCode code, const char* message) {
MG_State::pGLContext->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message)); MGB_CTX->RecordError(code, MakeUnique<GenericErrorInfo>("DirectVulkan", func, message));
} }
static Bool HasDistinctCompleteDepthStencilTextureAttachments( static Bool HasDistinctCompleteDepthStencilTextureAttachments(
@@ -1300,7 +1301,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
static void RecordUnsupportedFramebufferError(const char* func) { static void RecordUnsupportedFramebufferError(const char* func) {
MG_State::pGLContext->RecordError( MGB_CTX->RecordError(
ErrorCode::InvalidFramebufferOperation, ErrorCode::InvalidFramebufferOperation,
MakeUnique<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"DirectVulkan", func, "DirectVulkan", func,
@@ -2768,7 +2769,7 @@ void main() {
// glReadPixels final conversion: GL_CLAMP_READ_COLOR defaults to GL_FIXED_ONLY, // glReadPixels final conversion: GL_CLAMP_READ_COLOR defaults to GL_FIXED_ONLY,
// clamping fixed-point (normalized) buffers to [0,1] - visible for SNORM reads. // clamping fixed-point (normalized) buffers to [0,1] - visible for SNORM reads.
if (applyReadColorClamp && wideType == GL_FLOAT) { if (applyReadColorClamp && wideType == GL_FLOAT) {
const GLenum clampMode = MG_State::pGLContext->GetClampReadColor(); const GLenum clampMode = MGB_CTX->GetClampReadColor();
const Bool clamp = clampMode == GL_TRUE || const Bool clamp = clampMode == GL_TRUE ||
(clampMode == GL_FIXED_ONLY && !IsFloatingPointReadbackFormat(srcFormat)); (clampMode == GL_FIXED_ONLY && !IsFloatingPointReadbackFormat(srcFormat));
if (clamp) { if (clamp) {
@@ -2985,7 +2986,7 @@ void main() {
inline ProgramFactory::CompileOptionFlags GetShaderTransformFlags(VkSurfaceTransformFlagBitsKHR preTransform) { inline ProgramFactory::CompileOptionFlags GetShaderTransformFlags(VkSurfaceTransformFlagBitsKHR preTransform) {
ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionBit::PositionZRemap; ProgramFactory::CompileOptionFlags flags = ProgramFactory::CompileOptionBit::PositionZRemap;
const auto& currentDrawFBO = const auto& currentDrawFBO =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (currentDrawFBO != nullptr && currentDrawFBO->IsDefaultFramebuffer()) { if (currentDrawFBO != nullptr && currentDrawFBO->IsDefaultFramebuffer()) {
flags |= ProgramFactory::CompileOptionBit::PositionYFlip; flags |= ProgramFactory::CompileOptionBit::PositionYFlip;
// gl_FragCoord follows the same rule the default-framebuffer RECTANGLES follow // gl_FragCoord follows the same rule the default-framebuffer RECTANGLES follow
@@ -3445,8 +3446,8 @@ void main() {
// with restart off it is a legitimate index and excluding it would truncate the // with restart off it is a legitimate index and excluding it would truncate the
// converted stream by exactly that vertex. // converted stream by exactly that vertex.
const Bool primitiveRestartActive = const Bool primitiveRestartActive =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) || MGB_CTX->IsCapabilityEnabled(CapabilityInput::PrimitiveRestart) ||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex); MGB_CTX->IsCapabilityEnabled(CapabilityInput::PrimitiveRestartFixedIndex);
const Uint32 restartSentinel = indexSize == 1 ? 0xFFu : indexSize == 2 ? 0xFFFFu : 0xFFFFFFFFu; const Uint32 restartSentinel = indexSize == 1 ? 0xFFu : indexSize == 2 ? 0xFFFFu : 0xFFFFFFFFu;
Uint32 maxIndex = 0; Uint32 maxIndex = 0;
Bool sawIndex = false; Bool sawIndex = false;
@@ -3923,7 +3924,7 @@ void main() {
} }
const auto glType = programObj.vertexInputTypes[location]; const auto glType = programObj.vertexInputTypes[location];
const auto& currentValue = MG_State::pGLContext->GetCurrentVertexAttribute(location); const auto& currentValue = MGB_CTX->GetCurrentVertexAttribute(location);
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
const void* sourceData = nullptr; const void* sourceData = nullptr;
VkDeviceSize sourceSize = 0; VkDeviceSize sourceSize = 0;
@@ -4057,7 +4058,7 @@ void main() {
Bool substituteRestart = false; Bool substituteRestart = false;
// One bulk parameters fetch instead of up to three accessor calls per indexed // One bulk parameters fetch instead of up to three accessor calls per indexed
// draw; all three inputs are pure reads of these fields. // draw; all three inputs are pure reads of these fields.
const RenderStateParameters& rsp = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& rsp = MGB_CTX->GetRenderStateParameters();
if (rsp.PrimitiveRestartEnabled && !rsp.PrimitiveRestartFixedIndexEnabled) { if (rsp.PrimitiveRestartEnabled && !rsp.PrimitiveRestartFixedIndexEnabled) {
const Uint32 restartIndex = rsp.PrimitiveRestartIndex; const Uint32 restartIndex = rsp.PrimitiveRestartIndex;
const Uint32 fixedMax = MG_Util::FixedRestartIndexForGLType(pIndexBufferView->indexType); const Uint32 fixedMax = MG_Util::FixedRestartIndexForGLType(pIndexBufferView->indexType);
@@ -4812,9 +4813,9 @@ void main() {
Uint32 VulkanRenderer::ResolveEffectiveSampleMask(VkSampleCountFlagBits rasterizationSamples) const { Uint32 VulkanRenderer::ResolveEffectiveSampleMask(VkSampleCountFlagBits rasterizationSamples) const {
constexpr Uint32 kFullCoverage = 0xffffffffu; constexpr Uint32 kFullCoverage = 0xffffffffu;
if (rasterizationSamples == VK_SAMPLE_COUNT_1_BIT) return kFullCoverage; if (rasterizationSamples == VK_SAMPLE_COUNT_1_BIT) return kFullCoverage;
if (!MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::Multisample)) return kFullCoverage; if (!MGB_CTX->IsCapabilityEnabled(CapabilityInput::Multisample)) return kFullCoverage;
if (!MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::SampleMask)) return kFullCoverage; if (!MGB_CTX->IsCapabilityEnabled(CapabilityInput::SampleMask)) return kFullCoverage;
return MG_State::pGLContext->GetRenderStateParameters().SampleMaskValue; return MGB_CTX->GetRenderStateParameters().SampleMaskValue;
} }
Uint64 VulkanRenderer::ComputePipelineStateHash(Uint32 colorAttachmentCount, Uint64 VulkanRenderer::ComputePipelineStateHash(Uint32 colorAttachmentCount,
@@ -4825,7 +4826,7 @@ void main() {
// field (RenderState.cpp), so the hashed values are bit-identical. This runs on // field (RenderState.cpp), so the hashed values are bit-identical. This runs on
// every draw whose pipeline-state version moved (a per-draw GL_BLEND toggle), // every draw whose pipeline-state version moved (a per-draw GL_BLEND toggle),
// where the accessor-call overhead dominated the hash itself. // where the accessor-call overhead dominated the hash itself.
const RenderStateParameters& p = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& p = MGB_CTX->GetRenderStateParameters();
Uint64 capabilityBits = 0; Uint64 capabilityBits = 0;
capabilityBits |= p.CullFaceEnabled ? 1ull << 0 : 0; capabilityBits |= p.CullFaceEnabled ? 1ull << 0 : 0;
capabilityBits |= p.DepthTestEnabled ? 1ull << 1 : 0; capabilityBits |= p.DepthTestEnabled ? 1ull << 1 : 0;
@@ -4937,7 +4938,7 @@ void main() {
if (!(aspects & DrawSetupAspect::IndexBuffer) || pIndexBufferView == nullptr) { if (!(aspects & DrawSetupAspect::IndexBuffer) || pIndexBufferView == nullptr) {
return false; return false;
} }
const RenderStateParameters& rsp = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& rsp = MGB_CTX->GetRenderStateParameters();
if (rsp.PrimitiveRestartFixedIndexEnabled) { if (rsp.PrimitiveRestartFixedIndexEnabled) {
return true; return true;
} }
@@ -4981,7 +4982,7 @@ void main() {
// the VALUE hash of that subset, never the version itself: the version is monotonic, so // the VALUE hash of that subset, never the version itself: the version is monotonic, so
// per-draw state flips (GL_BLEND toggles) would otherwise miss entries the memo holds. // per-draw state flips (GL_BLEND toggles) would otherwise miss entries the memo holds.
// The version only guards recomputing the hash - unchanged version, unchanged bytes. // The version only guards recomputing the hash - unchanged version, unchanged bytes.
const Uint renderStateVersion = MG_State::pGLContext->GetPipelineStateVersion(); const Uint renderStateVersion = MGB_CTX->GetPipelineStateVersion();
if (!m_pipelineStateHashValid || m_pipelineStateHashVersion != renderStateVersion || if (!m_pipelineStateHashValid || m_pipelineStateHashVersion != renderStateVersion ||
m_pipelineStateHashColorCount != renderPassEntry.colorAttachmentCount || m_pipelineStateHashColorCount != renderPassEntry.colorAttachmentCount ||
m_pipelineStateHashSampleCount != renderPassEntry.sampleCount) { m_pipelineStateHashSampleCount != renderPassEntry.sampleCount) {
@@ -5169,22 +5170,22 @@ void main() {
syntheticVertexInputState.pNext = vis.state.pNext; syntheticVertexInputState.pNext = vis.state.pNext;
pipelineVertexInputState = &syntheticVertexInputState; pipelineVertexInputState = &syntheticVertexInputState;
} }
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace); auto cullFaceEnabled = MGB_CTX->IsCapabilityEnabled(CapabilityInput::CullFace);
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest); auto depthTestEnabled = MGB_CTX->IsCapabilityEnabled(CapabilityInput::DepthTest);
auto polygonOffsetFillEnabled = auto polygonOffsetFillEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) && MGB_CTX->IsCapabilityEnabled(CapabilityInput::PolygonOffsetFill) &&
DrawModeUsesPolygonFill(mode); DrawModeUsesPolygonFill(mode);
auto rasterizerDiscardEnabled = auto rasterizerDiscardEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard); MGB_CTX->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard);
auto colorLogicOpEnabled = auto colorLogicOpEnabled =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled; MGB_CTX->IsCapabilityEnabled(CapabilityInput::ColorLogicOp) && m_logicOpFeatureEnabled;
auto stencilTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest); auto stencilTestEnabled = MGB_CTX->IsCapabilityEnabled(CapabilityInput::StencilTest);
// A framebuffer without a depth (stencil) attachment behaves as if the depth // A framebuffer without a depth (stencil) attachment behaves as if the depth
// (stencil) test always passes and nothing is written - even when the bound // (stencil) test always passes and nothing is written - even when the bound
// image is a packed depth-stencil texture attached through only one half. // image is a packed depth-stencil texture attached through only one half.
{ {
const auto& gatingFbo = const auto& gatingFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (gatingFbo != nullptr && !gatingFbo->IsDefaultFramebuffer()) { if (gatingFbo != nullptr && !gatingFbo->IsDefaultFramebuffer()) {
const auto& depthAtt = gatingFbo->GetAttachment(MobileGL::FramebufferAttachmentType::Depth); const auto& depthAtt = gatingFbo->GetAttachment(MobileGL::FramebufferAttachmentType::Depth);
const auto& stencilAtt = gatingFbo->GetAttachment(MobileGL::FramebufferAttachmentType::Stencil); const auto& stencilAtt = gatingFbo->GetAttachment(MobileGL::FramebufferAttachmentType::Stencil);
@@ -5196,10 +5197,10 @@ void main() {
} }
} }
} }
const StencilFaceState& frontStencil = MG_State::pGLContext->GetStencilState(StencilFace::Front); const StencilFaceState& frontStencil = MGB_CTX->GetStencilState(StencilFace::Front);
const StencilFaceState& backStencil = MG_State::pGLContext->GetStencilState(StencilFace::Back); const StencilFaceState& backStencil = MGB_CTX->GetStencilState(StencilFace::Back);
const VkPolygonMode requestedPolygonMode = const VkPolygonMode requestedPolygonMode =
MG_Util::ConvertPolygonModeToVkEnum(MG_State::pGLContext->GetPolygonModeFront()); MG_Util::ConvertPolygonModeToVkEnum(MGB_CTX->GetPolygonModeFront());
// VK_POLYGON_MODE_LINE/_POINT require the fillModeNonSolid device feature; fall back to // VK_POLYGON_MODE_LINE/_POINT require the fillModeNonSolid device feature; fall back to
// VK_POLYGON_MODE_FILL when the device lacks it. // VK_POLYGON_MODE_FILL when the device lacks it.
const VkPolygonMode effectivePolygonMode = const VkPolygonMode effectivePolygonMode =
@@ -5284,18 +5285,18 @@ void main() {
// driver's own rate. Both halves move the render state's PIPELINE version, so a cached // driver's own rate. Both halves move the render state's PIPELINE version, so a cached
// pipeline built at the old rate cannot be handed back for the new one. // pipeline built at the old rate cannot be handed back for the new one.
.sampleShadingEnable = m_sampleRateShadingFeatureEnabled && .sampleShadingEnable = m_sampleRateShadingFeatureEnabled &&
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::SampleShading), MGB_CTX->IsCapabilityEnabled(CapabilityInput::SampleShading),
.minSampleShading = MG_State::pGLContext->GetMinSampleShadingValue(), .minSampleShading = MGB_CTX->GetMinSampleShadingValue(),
// Word 1 keeps its all-ones initialiser: GL has no state for samples 32..63. // Word 1 keeps its all-ones initialiser: 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,
.primitiveRestartEnable = primitiveRestartEnabled, .primitiveRestartEnable = primitiveRestartEnabled,
.patchControlPoints = static_cast<Uint32>(MG_State::pGLContext->GetPatchVertices()), .patchControlPoints = static_cast<Uint32>(MGB_CTX->GetPatchVertices()),
.viewportCount = ResolveDrawViewportCount(programObj.writesViewportIndexBuiltin), .viewportCount = ResolveDrawViewportCount(programObj.writesViewportIndexBuiltin),
.polygonMode = effectivePolygonMode, .polygonMode = effectivePolygonMode,
.cullMode = cullFaceEnabled .cullMode = cullFaceEnabled
? MG_Util::ConvertCullFaceModeToVkEnum(MG_State::pGLContext->GetCullFaceMode(), invertClockwise) ? MG_Util::ConvertCullFaceModeToVkEnum(MGB_CTX->GetCullFaceMode(), invertClockwise)
: VK_CULL_MODE_NONE, : VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_CLOCKWISE, .frontFace = VK_FRONT_FACE_CLOCKWISE,
// Read the geometry stage off the program's own shader list rather than // Read the geometry stage off the program's own shader list rather than
@@ -5309,13 +5310,13 @@ void main() {
.provokingVertexMode = SelectProvokingVertexMode( .provokingVertexMode = SelectProvokingVertexMode(
vkTopology, ProgramCapturesXfbFromGeometryStage(program)), vkTopology, ProgramCapturesXfbFromGeometryStage(program)),
.depthTestEnable = depthTestEnabled, .depthTestEnable = depthTestEnabled,
.depthWriteEnable = depthTestEnabled && MG_State::pGLContext->GetDepthMask(), .depthWriteEnable = depthTestEnabled && MGB_CTX->GetDepthMask(),
.depthBiasEnable = polygonOffsetFillEnabled, .depthBiasEnable = polygonOffsetFillEnabled,
.rasterizerDiscardEnable = rasterizerDiscardEnabled, .rasterizerDiscardEnable = rasterizerDiscardEnabled,
.logicOpEnable = colorLogicOpEnabled, .logicOpEnable = colorLogicOpEnabled,
.stencilTestEnable = stencilTestEnabled, .stencilTestEnable = stencilTestEnabled,
.depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MG_State::pGLContext->GetDepthFunc()), .depthCompareOp = MG_Util::ConvertDepthTestFuncToVkEnum(MGB_CTX->GetDepthFunc()),
.logicOp = MG_Util::ConvertLogicOperationToVkEnum(MG_State::pGLContext->GetLogicOp()), .logicOp = MG_Util::ConvertLogicOperationToVkEnum(MGB_CTX->GetLogicOp()),
.frontStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.FailOp), .frontStencilFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.FailOp),
.frontStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthPassOp), .frontStencilPassOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthPassOp),
.frontStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthFailOp), .frontStencilDepthFailOp = MG_Util::ConvertStencilOperationToVkEnum(frontStencil.PassDepthFailOp),
@@ -5351,8 +5352,8 @@ void main() {
// handed back after the application changed them. // handed back after the application changed them.
if (programObj.needsPassthroughTessControl && programObj.passthroughTessControlEmulatable && if (programObj.needsPassthroughTessControl && programObj.passthroughTessControlEmulatable &&
vkTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { vkTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
const FloatVec4& defaultOuterLevel = MG_State::pGLContext->GetPatchDefaultOuterLevel(); const FloatVec4& defaultOuterLevel = MGB_CTX->GetPatchDefaultOuterLevel();
const FloatVec2& defaultInnerLevel = MG_State::pGLContext->GetPatchDefaultInnerLevel(); const FloatVec2& defaultInnerLevel = MGB_CTX->GetPatchDefaultInnerLevel();
payload.passthroughTessControlKey = ProgramFactory::ComputePassthroughTessControlKey( payload.passthroughTessControlKey = ProgramFactory::ComputePassthroughTessControlKey(
payload.patchControlPoints, defaultOuterLevel, defaultInnerLevel, payload.patchControlPoints, defaultOuterLevel, defaultInnerLevel,
programObj.passthroughPerVertexMembers); programObj.passthroughPerVertexMembers);
@@ -5404,7 +5405,7 @@ void main() {
"GetOrCreatePipeline: colorAttachmentCount=%u exceeds payload capacity", "GetOrCreatePipeline: colorAttachmentCount=%u exceeds payload capacity",
payload.colorAttachmentCount); payload.colorAttachmentCount);
const auto& drawFboBinding = const auto& drawFboBinding =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
MOBILEGL_ASSERT(drawFboBinding != nullptr, "GetOrCreatePipeline: draw framebuffer is null"); MOBILEGL_ASSERT(drawFboBinding != nullptr, "GetOrCreatePipeline: draw framebuffer is null");
const Bool isDefaultDrawFbo = drawFboBinding->IsDefaultFramebuffer(); const Bool isDefaultDrawFbo = drawFboBinding->IsDefaultFramebuffer();
const auto& drawBuffers = drawFboBinding->GetDrawBuffers(); const auto& drawBuffers = drawFboBinding->GetDrawBuffers();
@@ -5432,14 +5433,14 @@ void main() {
BlendFactor dstAlpha = BlendFactor::Zero; BlendFactor dstAlpha = BlendFactor::Zero;
BlendEquation colorEquation = BlendEquation::Add; BlendEquation colorEquation = BlendEquation::Add;
BlendEquation alphaEquation = BlendEquation::Add; BlendEquation alphaEquation = BlendEquation::Add;
MG_State::pGLContext->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha); MGB_CTX->GetBlendFuncIndexed(i, srcRGB, dstRGB, srcAlpha, dstAlpha);
MG_State::pGLContext->GetBlendEquationIndexed(i, colorEquation, alphaEquation); MGB_CTX->GetBlendEquationIndexed(i, colorEquation, alphaEquation);
const Bool blendEnabled = MG_State::pGLContext->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i); const Bool blendEnabled = MGB_CTX->IsCapabilityEnabledIndexed(CapabilityInput::Blend, i);
// Per-draw-buffer color write mask (glColorMaski). Divergent per-attachment masks require // Per-draw-buffer color write mask (glColorMaski). Divergent per-attachment masks require
// the independentBlend device feature; when it is absent, fall back to draw buffer 0's // the independentBlend device feature; when it is absent, fall back to draw buffer 0's
// mask for every attachment (matching the non-indexed glColorMask broadcast). // mask for every attachment (matching the non-indexed glColorMask broadcast).
const BoolVec4 bufferMask = const BoolVec4 bufferMask =
MG_State::pGLContext->GetColorMaskIndexed(m_independentBlendFeatureEnabled ? i : 0); MGB_CTX->GetColorMaskIndexed(m_independentBlendFeatureEnabled ? i : 0);
VkColorComponentFlags attachmentColorWriteMask = static_cast<VkColorComponentFlags>( VkColorComponentFlags attachmentColorWriteMask = static_cast<VkColorComponentFlags>(
(bufferMask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) | (bufferMask.r() ? VK_COLOR_COMPONENT_R_BIT : 0u) |
(bufferMask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) | (bufferMask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) |
@@ -5855,7 +5856,7 @@ void main() {
VkRect2D VulkanRenderer::ComputeGLScissorRect(Uint32 index, const IntVec2& extent, VkRect2D VulkanRenderer::ComputeGLScissorRect(Uint32 index, const IntVec2& extent,
VkSurfaceTransformFlagBitsKHR preTransform, VkSurfaceTransformFlagBitsKHR preTransform,
Bool isDefaultFbo) const { Bool isDefaultFbo) const {
const auto& parameters = MG_State::pGLContext->GetRenderStateParameters(); const auto& parameters = MGB_CTX->GetRenderStateParameters();
if ((parameters.ScissorTestEnabledMask & (1u << index)) == 0) { if ((parameters.ScissorTestEnabledMask & (1u << index)) == 0) {
VkRect2D full{}; VkRect2D full{};
full.offset = {0, 0}; full.offset = {0, 0};
@@ -5916,7 +5917,7 @@ void main() {
// One compare for the whole tail: see the gate's declaration in // One compare for the whole tail: see the gate's declaration in
// DynamicStateShadow for why (version, extent, default-FBO flag) pins every // DynamicStateShadow for why (version, extent, default-FBO flag) pins every
// input the six Apply* below read. // input the six Apply* below read.
const Uint paramsVersion = MG_State::pGLContext->GetRenderStateParametersVersion(); const Uint paramsVersion = MGB_CTX->GetRenderStateParametersVersion();
if (shadow.dynamicTailValid && shadow.dynamicTailParamsVersion == paramsVersion && if (shadow.dynamicTailValid && shadow.dynamicTailParamsVersion == paramsVersion &&
shadow.dynamicTailExtentX == extent.x() && shadow.dynamicTailExtentY == extent.y() && shadow.dynamicTailExtentX == extent.x() && shadow.dynamicTailExtentY == extent.y() &&
shadow.dynamicTailIsDefaultFbo == isDefaultFbo) { shadow.dynamicTailIsDefaultFbo == isDefaultFbo) {
@@ -5940,7 +5941,7 @@ void main() {
// re-derive the value its shadow already holds. // re-derive the value its shadow already holds.
DynamicStateShadow::DynamicTailKey key; DynamicStateShadow::DynamicTailKey key;
{ {
const RenderStateParameters& p = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& p = MGB_CTX->GetRenderStateParameters();
// Viewport 0 and its depth range: ApplyGLViewportState reads exactly those two // Viewport 0 and its depth range: ApplyGLViewportState reads exactly those two
// (per-index state for indices > 0 is keyed separately, see multiViewportKey below). // (per-index state for indices > 0 is keyed separately, see multiViewportKey below).
key.viewport[0] = p.Viewports[0].x(); key.viewport[0] = p.Viewports[0].x();
@@ -6016,7 +6017,7 @@ void main() {
MOBILEGL_ASSERT( MOBILEGL_ASSERT(
[&] { [&] {
const auto& fbo = const auto& fbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
return isDefaultFbo == (fbo != nullptr && fbo->IsDefaultFramebuffer()); return isDefaultFbo == (fbo != nullptr && fbo->IsDefaultFramebuffer());
}(), }(),
"GetBaseTransformFlagsRaw: isDefaultFbo does not match the bound draw framebuffer"); "GetBaseTransformFlagsRaw: isDefaultFbo does not match the bound draw framebuffer");
@@ -6040,7 +6041,7 @@ void main() {
// Entry select: by the draw program's lifetime id, MRU first (the id pins // Entry select: by the draw program's lifetime id, MRU first (the id pins
// the entry; every other fact is re-guarded below, so probing a stale // the entry; every other fact is re-guarded below, so probing a stale
// entry can only decline, never serve stale state). // entry can only decline, never serve stale state).
const auto& program = *MG_State::pGLContext->GetProgramForDraw(); const auto& program = *MGB_CTX->GetProgramForDraw();
const Uint64 programLifetimeId = program.GetLifetimeId(); const Uint64 programLifetimeId = program.GetLifetimeId();
SetupDrawSnapshot* snapPtr = nullptr; SetupDrawSnapshot* snapPtr = nullptr;
{ {
@@ -6088,7 +6089,7 @@ void main() {
// captured draw after glBeginTransformFeedback would bind the undecorated // captured draw after glBeginTransformFeedback would bind the undecorated
// variant and silently capture nothing while the CPU bookkeeping advances. // variant and silently capture nothing while the CPU bookkeeping advances.
const Bool wantsXfbCapture = m_transformFeedbackFeatureEnabled && const Bool wantsXfbCapture = m_transformFeedbackFeatureEnabled &&
MG_State::pGLContext->IsTransformFeedbackActive() && MGB_CTX->IsTransformFeedbackActive() &&
program.GetTransformFeedbackVaryingCount() > 0; program.GetTransformFeedbackVaryingCount() > 0;
const Bool snapHasXfbCapture = const Bool snapHasXfbCapture =
static_cast<Bool>(ProgramFactory::CompileOptionFlags(snap.resolvedTransformFlags) & static_cast<Bool>(ProgramFactory::CompileOptionFlags(snap.resolvedTransformFlags) &
@@ -6102,12 +6103,12 @@ void main() {
// buffer binds (re-run every draw anyway). Declining here would send every // buffer binds (re-run every draw anyway). Declining here would send every
// draw of a VAO-cycling stream (Minecraft chunk rendering) through the full // draw of a VAO-cycling stream (Minecraft chunk rendering) through the full
// path, re-resolving descriptors and texture layouts nothing invalidated. // path, re-resolving descriptors and texture layouts nothing invalidated.
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
const Bool vaoMoved = const Bool vaoMoved =
static_cast<const void*>(&vao) != snap.vao || vao.GetLifetimeId() != snap.vaoLifetimeId || static_cast<const void*>(&vao) != snap.vao || vao.GetLifetimeId() != snap.vaoLifetimeId ||
vao.GetConfigVersion() != snap.vaoConfigVersion; vao.GetConfigVersion() != snap.vaoConfigVersion;
const auto& drawFbo = const auto& drawFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (static_cast<const void*>(drawFbo.get()) != snap.drawFbo || if (static_cast<const void*>(drawFbo.get()) != snap.drawFbo ||
drawFbo->GetLifetimeId() != snap.drawFboLifetimeId || drawFbo->GetLifetimeId() != snap.drawFboLifetimeId ||
drawFbo->GetObjectVersion() != snap.fboVersion) { drawFbo->GetObjectVersion() != snap.fboVersion) {
@@ -6118,8 +6119,8 @@ void main() {
// back on what the snapshot already describes (a GL_BLEND toggle between // back on what the snapshot already describes (a GL_BLEND toggle between
// two draws, a redundant glBindSampler), and declining here sends every // two draws, a redundant glBindSampler), and declining here sends every
// such draw through the full SetupDraw. // such draw through the full SetupDraw.
const Uint renderStateVersion = MG_State::pGLContext->GetPipelineStateVersion(); const Uint renderStateVersion = MGB_CTX->GetPipelineStateVersion();
const Uint64 bindGeneration = MG_State::pGLContext->GetTextureBindGeneration(); const Uint64 bindGeneration = MGB_CTX->GetTextureBindGeneration();
const Bool renderStateMoved = renderStateVersion != snap.renderStateVersion; const Bool renderStateMoved = renderStateVersion != snap.renderStateVersion;
const Bool bindsMoved = bindGeneration != snap.bindGeneration; const Bool bindsMoved = bindGeneration != snap.bindGeneration;
if (renderStateMoved) { if (renderStateMoved) {
@@ -6127,7 +6128,7 @@ void main() {
// flavor input (depth/stencil participation); a flip of that must take // flavor input (depth/stencil participation); a flip of that must take
// the full path's pass selection. One bulk parameters fetch instead of // the full path's pass selection. One bulk parameters fetch instead of
// two capability-accessor calls; both are pure reads of the same fields. // two capability-accessor calls; both are pure reads of the same fields.
const RenderStateParameters& rsp = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& rsp = MGB_CTX->GetRenderStateParameters();
const Bool drawUsesDepthStencil = rsp.DepthTestEnabled || rsp.StencilTestEnabled; const Bool drawUsesDepthStencil = rsp.DepthTestEnabled || rsp.StencilTestEnabled;
if (drawUsesDepthStencil != snap.drawUsesDepthStencil) { if (drawUsesDepthStencil != snap.drawUsesDepthStencil) {
return false; return false;
@@ -6301,7 +6302,7 @@ void main() {
if (contentSum != snap.sampledContentSum || paramsSum != snap.sampledParamsSum) { if (contentSum != snap.sampledContentSum || paramsSum != snap.sampledParamsSum) {
return false; return false;
} }
const Uint64 samplingResolutionGeneration = MG_State::pGLContext->GetSamplingResolutionGeneration(); const Uint64 samplingResolutionGeneration = MGB_CTX->GetSamplingResolutionGeneration();
if (samplingResolutionGeneration != snap.samplingResolutionGeneration) { if (samplingResolutionGeneration != snap.samplingResolutionGeneration) {
// Decline, not re-arm: snap.resolvedTransformFlags bakes the // Decline, not re-arm: snap.resolvedTransformFlags bakes the
// ExplicitLod0Sampling verdict, which reads the effective sampler's // ExplicitLod0Sampling verdict, which reads the effective sampler's
@@ -6431,7 +6432,7 @@ void main() {
// was cancelled has no usable optimized module - and on an in-place // was cancelled has no usable optimized module - and on an in-place
// SanitizeAndOptimizeBinary failure GetGeneratedSpirv() still holds the RAW // SanitizeAndOptimizeBinary failure GetGeneratedSpirv() still holds the RAW
// glslang words, which must never reach vkCreateShaderModule. Drop the draw. // glslang words, which must never reach vkCreateShaderModule. Drop the draw.
const auto& drawProgram = *MG_State::pGLContext->GetProgramForDraw(); const auto& drawProgram = *MGB_CTX->GetProgramForDraw();
if (!drawProgram.GetLinkStatus() || !drawProgram.GetSpirvStatus()) { if (!drawProgram.GetLinkStatus() || !drawProgram.GetSpirvStatus()) {
MGLOG_D("SetupDraw skipped: program=%u is linked=%d spirv=%d", MGLOG_D("SetupDraw skipped: program=%u is linked=%d spirv=%d",
drawProgram.GetExternalIndex(), static_cast<int>(drawProgram.GetLinkStatus()), drawProgram.GetExternalIndex(), static_cast<int>(drawProgram.GetLinkStatus()),
@@ -6461,15 +6462,15 @@ void main() {
MG_Util::PipeStats::AddCalls(MG_Util::PipeStats::CallClass::AccessorCalls, 3); MG_Util::PipeStats::AddCalls(MG_Util::PipeStats::CallClass::AccessorCalls, 3);
} }
const auto& drawFbo = const auto& drawFbo =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (drawFbo != nullptr && IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) { if (drawFbo != nullptr && IsUnsupportedFramebufferForDirectVulkan(*drawFbo)) {
// Nothing was mutated: other entries' per-probe guards (FBO identity + // Nothing was mutated: other entries' per-probe guards (FBO identity +
// version among them) stay authoritative, so none need invalidating. // version among them) stay authoritative, so none need invalidating.
RecordUnsupportedFramebufferError(__func__); RecordUnsupportedFramebufferError(__func__);
return false; return false;
} }
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
const auto& program = *MG_State::pGLContext->GetProgramForDraw(); const auto& program = *MGB_CTX->GetProgramForDraw();
// The fast path declined (or had no entry for this program): whatever THIS // The fast path declined (or had no entry for this program): whatever THIS
// program's entry saw may be stale, and the full path below mutates state as // program's entry saw may be stale, and the full path below mutates state as
// it goes, so the entry must not stay matchable if that path fails mid-way. // it goes, so the entry must not stay matchable if that path fails mid-way.
@@ -6509,7 +6510,7 @@ void main() {
ProgramFactory::CompileOptionFlags transformFlags = ProgramFactory::CompileOptionFlags transformFlags =
ProgramFactory::CompileOptionFlags(GetBaseTransformFlagsRaw(drawFboIsDefault)); ProgramFactory::CompileOptionFlags(GetBaseTransformFlagsRaw(drawFboIsDefault));
// Captured draws take the xfb-decorated program variant. // Captured draws take the xfb-decorated program variant.
if (m_transformFeedbackFeatureEnabled && MG_State::pGLContext->IsTransformFeedbackActive() && if (m_transformFeedbackFeatureEnabled && MGB_CTX->IsTransformFeedbackActive() &&
program.GetTransformFeedbackVaryingCount() > 0) { program.GetTransformFeedbackVaryingCount() > 0) {
transformFlags |= ProgramFactory::CompileOptionBit::XfbCapture; transformFlags |= ProgramFactory::CompileOptionBit::XfbCapture;
} }
@@ -6523,13 +6524,13 @@ void main() {
{ {
const Uint64 lodProgramLifetimeId = program.GetLifetimeId(); const Uint64 lodProgramLifetimeId = program.GetLifetimeId();
const Uint32 lodProgramVersion = program.GetBackendStateVersion(); const Uint32 lodProgramVersion = program.GetBackendStateVersion();
const Uint64 lodBindGeneration = MG_State::pGLContext->GetTextureBindGeneration(); const Uint64 lodBindGeneration = MGB_CTX->GetTextureBindGeneration();
// The probe also reads the EFFECTIVE sampler's filters/aniso/LOD range // The probe also reads the EFFECTIVE sampler's filters/aniso/LOD range
// (ProgramSamplesOnlySingleLevelTextures), and those setters bump ONLY the // (ProgramSamplesOnlySingleLevelTextures), and those setters bump ONLY the
// sampling-resolution generation - not the texture params version the sum // sampling-resolution generation - not the texture params version the sum
// below covers. Without this key a filter/aniso change would keep serving // below covers. Without this key a filter/aniso change would keep serving
// the stale verdict. // the stale verdict.
const Uint64 lodSamplingGeneration = MG_State::pGLContext->GetSamplingResolutionGeneration(); const Uint64 lodSamplingGeneration = MGB_CTX->GetSamplingResolutionGeneration();
Bool lodMemoHit = false; Bool lodMemoHit = false;
if (m_lastLodDecisionValid && m_lastSampledSetValid && if (m_lastLodDecisionValid && m_lastSampledSetValid &&
m_lastLodProgramLifetimeId == lodProgramLifetimeId && m_lastLodProgramLifetimeId == lodProgramLifetimeId &&
@@ -6647,7 +6648,7 @@ void main() {
{ {
const Uint64 programLifetimeId = program.GetLifetimeId(); const Uint64 programLifetimeId = program.GetLifetimeId();
const Uint32 programVersion = program.GetBackendStateVersion(); const Uint32 programVersion = program.GetBackendStateVersion();
const Uint64 bindGeneration = MG_State::pGLContext->GetTextureBindGeneration(); const Uint64 bindGeneration = MGB_CTX->GetTextureBindGeneration();
// The bind generation alone stopped covering this set the moment ResolveSampledBinding // The bind generation alone stopped covering this set the moment ResolveSampledBinding
// started asking SamplesAsIncompleteTexture: membership now depends on the effective // started asking SamplesAsIncompleteTexture: membership now depends on the effective
// sampler PARAMETERS (MIN_FILTER decides whether the mip chain is read at all) and on // sampler PARAMETERS (MIN_FILTER decides whether the mip chain is read at all) and on
@@ -6666,7 +6667,7 @@ void main() {
// object a unit carries goes through TextureUnit::SetSamplerObject and moves the bind // object a unit carries goes through TextureUnit::SetSamplerObject and moves the bind
// generation instead. Same term the SetupDrawSnapshot fast path and the LOD memo // generation instead. Same term the SetupDrawSnapshot fast path and the LOD memo
// already carry. // already carry.
const Uint64 samplingGeneration = MG_State::pGLContext->GetSamplingResolutionGeneration(); const Uint64 samplingGeneration = MGB_CTX->GetSamplingResolutionGeneration();
const Bool sampledSetUnchanged = const Bool sampledSetUnchanged =
m_lastSampledSetValid && m_lastSampledSetProgramLifetimeId == programLifetimeId && m_lastSampledSetValid && m_lastSampledSetProgramLifetimeId == programLifetimeId &&
m_lastSampledSetProgramVersion == programVersion && m_lastSampledSetProgramVersion == programVersion &&
@@ -6827,8 +6828,8 @@ void main() {
// pass flavor (GL: a disabled depth/stencil test neither reads nor writes // pass flavor (GL: a disabled depth/stencil test neither reads nor writes
// its buffer). // its buffer).
const Bool drawUsesDepthStencil = const Bool drawUsesDepthStencil =
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest) || MGB_CTX->IsCapabilityEnabled(CapabilityInput::DepthTest) ||
MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::StencilTest); MGB_CTX->IsCapabilityEnabled(CapabilityInput::StencilTest);
auto* renderPassEntry = auto* renderPassEntry =
m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired, drawUsesDepthStencil); m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired, drawUsesDepthStencil);
// nullptr: the framebuffer has an attachment DirectVulkan cannot represent (a texture the // nullptr: the framebuffer has an attachment DirectVulkan cannot represent (a texture the
@@ -6969,8 +6970,8 @@ void main() {
snap.fboVersion = drawFbo->GetObjectVersion(); snap.fboVersion = drawFbo->GetObjectVersion();
snap.drawFboIsDefault = drawFboIsDefault; snap.drawFboIsDefault = drawFboIsDefault;
snap.viewportCount = ResolveDrawViewportCount(programObj.writesViewportIndexBuiltin); snap.viewportCount = ResolveDrawViewportCount(programObj.writesViewportIndexBuiltin);
snap.renderStateVersion = MG_State::pGLContext->GetPipelineStateVersion(); snap.renderStateVersion = MGB_CTX->GetPipelineStateVersion();
snap.bindGeneration = MG_State::pGLContext->GetTextureBindGeneration(); snap.bindGeneration = MGB_CTX->GetTextureBindGeneration();
snap.baseTransformFlags = GetBaseTransformFlagsRaw(drawFboIsDefault); snap.baseTransformFlags = GetBaseTransformFlagsRaw(drawFboIsDefault);
snap.resolvedTransformFlags = transformFlags.GetRaw(); snap.resolvedTransformFlags = transformFlags.GetRaw();
snap.renderPassHash = nowActiveRenderPass->hash; snap.renderPassHash = nowActiveRenderPass->hash;
@@ -6996,7 +6997,7 @@ void main() {
snap.programObj = nullptr; snap.programObj = nullptr;
snap.programFactoryEpoch = 0; snap.programFactoryEpoch = 0;
} }
snap.samplingResolutionGeneration = MG_State::pGLContext->GetSamplingResolutionGeneration(); snap.samplingResolutionGeneration = MGB_CTX->GetSamplingResolutionGeneration();
Uint64 snapContentSum = 0; Uint64 snapContentSum = 0;
Uint64 snapParamsSum = 0; Uint64 snapParamsSum = 0;
// Per-entry copies of this draw's sampled set (the scratch vectors // Per-entry copies of this draw's sampled set (the scratch vectors
@@ -7033,7 +7034,7 @@ void main() {
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
// The DISPATCH accessor: with a pipeline bound this is its compute stage program // The DISPATCH accessor: with a pipeline bound this is its compute stage program
// itself, never the graphics composite (which carries no compute stage at all). // itself, never the graphics composite (which carries no compute stage at all).
const auto& program = *MG_State::pGLContext->GetProgramForDispatch(); const auto& program = *MGB_CTX->GetProgramForDispatch();
if (!program.GetLinkStatus() || !program.GetSpirvStatus()) { if (!program.GetLinkStatus() || !program.GetSpirvStatus()) {
MGLOG_E_ONCE("DispatchCompute skipped: program=%u has no optimized SPIR-V", MGLOG_E_ONCE("DispatchCompute skipped: program=%u has no optimized SPIR-V",
program.GetExternalIndex()); program.GetExternalIndex());
@@ -7085,7 +7086,7 @@ void main() {
m_textureManager->CollectGarbage(); m_textureManager->CollectGarbage();
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
// See DispatchCompute: the dispatch accessor, not the draw one. // See DispatchCompute: the dispatch accessor, not the draw one.
const auto& program = *MG_State::pGLContext->GetProgramForDispatch(); const auto& program = *MGB_CTX->GetProgramForDispatch();
if (!program.GetLinkStatus() || !program.GetSpirvStatus()) { if (!program.GetLinkStatus() || !program.GetSpirvStatus()) {
MGLOG_E_ONCE("DispatchComputeIndirect skipped: program=%u has no optimized SPIR-V", MGLOG_E_ONCE("DispatchComputeIndirect skipped: program=%u has no optimized SPIR-V",
program.GetExternalIndex()); program.GetExternalIndex());
@@ -7129,7 +7130,7 @@ void main() {
return; return;
} }
auto indirectBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject(); auto indirectBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject();
if (!indirectBuffer) { if (!indirectBuffer) {
MGLOG_E_ONCE("DispatchComputeIndirect skipped: GL_DISPATCH_INDIRECT_BUFFER is not bound"); MGLOG_E_ONCE("DispatchComputeIndirect skipped: GL_DISPATCH_INDIRECT_BUFFER is not bound");
return; return;
@@ -7203,10 +7204,10 @@ void main() {
VkClearRect clearRect{}; VkClearRect clearRect{};
clearRect.rect = framebuffer.IsDefaultFramebuffer() clearRect.rect = framebuffer.IsDefaultFramebuffer()
? MakeDefaultFramebufferScissorRect(MG_State::pGLContext->GetScissorBox(), ? MakeDefaultFramebufferScissorRect(MGB_CTX->GetScissorBox(),
renderPassEntry->extent, renderPassEntry->extent,
m_swapchainObject.GetPreTransform()) m_swapchainObject.GetPreTransform())
: MakeClampedScissorRect(MG_State::pGLContext->GetScissorBox(), renderPassEntry->extent); : MakeClampedScissorRect(MGB_CTX->GetScissorBox(), renderPassEntry->extent);
clearRect.baseArrayLayer = 0; clearRect.baseArrayLayer = 0;
// GL 3.3 §4.4.7: clearing a layered framebuffer clears every layer. // GL 3.3 §4.4.7: clearing a layered framebuffer clears every layer.
clearRect.layerCount = renderPassEntry->layers; clearRect.layerCount = renderPassEntry->layers;
@@ -7254,10 +7255,10 @@ void main() {
return; return;
} }
// GL 3.3 §3.1: when RASTERIZER_DISCARD is enabled, Clear and ClearBuffer* are ignored. // GL 3.3 §3.1: when RASTERIZER_DISCARD is enabled, Clear and ClearBuffer* are ignored.
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) { if (MGB_CTX->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) {
return; return;
} }
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get(); auto* fbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
MOBILEGL_ASSERT(fbo, "VulkanRenderer::Clear: draw framebuffer not found (fbo == nullptr)"); MOBILEGL_ASSERT(fbo, "VulkanRenderer::Clear: draw framebuffer not found (fbo == nullptr)");
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) { if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
RecordUnsupportedFramebufferError(__func__); RecordUnsupportedFramebufferError(__func__);
@@ -7265,16 +7266,16 @@ void main() {
} }
ClearFramebufferPayload payload { ClearFramebufferPayload payload {
.color = MG_State::pGLContext->GetClearColor(), .color = MGB_CTX->GetClearColor(),
.depth = MG_State::pGLContext->GetClearDepth(), .depth = MGB_CTX->GetClearDepth(),
.stencil = MG_State::pGLContext->GetClearStencil() .stencil = MGB_CTX->GetClearStencil()
}; };
// A render-pass loadOp clear always covers the complete attachment, while // A render-pass loadOp clear always covers the complete attachment, while
// OpenGL glClear is clipped by GL_SCISSOR_TEST. Blaze3D relies on this for // OpenGL glClear is clipped by GL_SCISSOR_TEST. Blaze3D relies on this for
// GuiItemAtlas: animated items clear only their atlas slot before being // GuiItemAtlas: animated items clear only their atlas slot before being
// redrawn. Queueing that clear as a loadOp erases every cached static item. // redrawn. Queueing that clear as a loadOp erases every cached static item.
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest)) { if (MGB_CTX->IsCapabilityEnabled(CapabilityInput::ScissorTest)) {
VkClearRect clearRect{}; VkClearRect clearRect{};
switch (PrepareScissoredClear(*fbo, clearRect)) { switch (PrepareScissoredClear(*fbo, clearRect)) {
case ScissoredClearPrep::NoOp: case ScissoredClearPrep::NoOp:
@@ -7297,7 +7298,7 @@ void main() {
continue; continue;
} }
const BoolVec4 colorMask = MG_State::pGLContext->GetColorMaskIndexed(drawBufferIndex); const BoolVec4 colorMask = MGB_CTX->GetColorMaskIndexed(drawBufferIndex);
if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) { if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) {
continue; continue;
} }
@@ -7324,7 +7325,7 @@ void main() {
} }
VkImageAspectFlags depthStencilAspects = 0; VkImageAspectFlags depthStencilAspects = 0;
if ((mask & GL_DEPTH_BUFFER_BIT) != 0 && MG_State::pGLContext->GetDepthMask()) { if ((mask & GL_DEPTH_BUFFER_BIT) != 0 && MGB_CTX->GetDepthMask()) {
const auto& depthAttachment = fbo->GetAttachment(FramebufferAttachmentType::Depth); const auto& depthAttachment = fbo->GetAttachment(FramebufferAttachmentType::Depth);
if (depthAttachment.IsComplete()) { if (depthAttachment.IsComplete()) {
depthStencilAspects |= VK_IMAGE_ASPECT_DEPTH_BIT; depthStencilAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
@@ -7337,7 +7338,7 @@ void main() {
// vkCmdClearAttachments writes every bit, so only a full (8-bit stencil) or // vkCmdClearAttachments writes every bit, so only a full (8-bit stencil) or
// zero mask can be expressed; treat a partial mask like a partial color mask. // zero mask can be expressed; treat a partial mask like a partial color mask.
const Uint32 stencilWriteMask = const Uint32 stencilWriteMask =
MG_State::pGLContext->GetStencilState(StencilFace::Front).WriteMask; MGB_CTX->GetStencilState(StencilFace::Front).WriteMask;
if ((stencilWriteMask & 0xFFu) == 0xFFu) { if ((stencilWriteMask & 0xFFu) == 0xFFu) {
depthStencilAspects |= VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
} else if (stencilWriteMask != 0) { } else if (stencilWriteMask != 0) {
@@ -7366,11 +7367,11 @@ void main() {
// gating for the deferred path: drop fully-masked planes, warn on partial // gating for the deferred path: drop fully-masked planes, warn on partial
// masks vkCmdClear*/loadOp clears cannot express. // masks vkCmdClear*/loadOp clears cannot express.
GLbitfield deferredMask = mask; GLbitfield deferredMask = mask;
if ((deferredMask & GL_DEPTH_BUFFER_BIT) != 0 && !MG_State::pGLContext->GetDepthMask()) { if ((deferredMask & GL_DEPTH_BUFFER_BIT) != 0 && !MGB_CTX->GetDepthMask()) {
deferredMask &= ~static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT); deferredMask &= ~static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT);
} }
if ((deferredMask & GL_STENCIL_BUFFER_BIT) != 0) { if ((deferredMask & GL_STENCIL_BUFFER_BIT) != 0) {
const Uint32 stencilWriteMask = MG_State::pGLContext->GetStencilState(StencilFace::Front).WriteMask; const Uint32 stencilWriteMask = MGB_CTX->GetStencilState(StencilFace::Front).WriteMask;
if ((stencilWriteMask & 0xFFu) != 0xFFu) { if ((stencilWriteMask & 0xFFu) != 0xFFu) {
if (stencilWriteMask != 0) { if (stencilWriteMask != 0) {
MGLOG_W_ONCE("DirectVulkan: deferred glClear with a partial stencil write mask is not supported"); MGLOG_W_ONCE("DirectVulkan: deferred glClear with a partial stencil write mask is not supported");
@@ -7386,7 +7387,7 @@ void main() {
if (drawBuffers[drawBufferIndex] == FramebufferAttachmentType::None) { if (drawBuffers[drawBufferIndex] == FramebufferAttachmentType::None) {
continue; continue;
} }
const BoolVec4 colorMask = MG_State::pGLContext->GetColorMaskIndexed(drawBufferIndex); const BoolVec4 colorMask = MGB_CTX->GetColorMaskIndexed(drawBufferIndex);
const Bool full = colorMask.r() && colorMask.g() && colorMask.b() && colorMask.a(); const Bool full = colorMask.r() && colorMask.g() && colorMask.b() && colorMask.a();
if (full) { if (full) {
anyFullMask = true; anyFullMask = true;
@@ -7407,7 +7408,7 @@ void main() {
if (attachmentType == FramebufferAttachmentType::None) { if (attachmentType == FramebufferAttachmentType::None) {
continue; continue;
} }
const BoolVec4 colorMask = MG_State::pGLContext->GetColorMaskIndexed(drawBufferIndex); const BoolVec4 colorMask = MGB_CTX->GetColorMaskIndexed(drawBufferIndex);
if (!(colorMask.r() && colorMask.g() && colorMask.b() && colorMask.a())) { if (!(colorMask.r() && colorMask.g() && colorMask.b() && colorMask.a())) {
continue; continue;
} }
@@ -7436,7 +7437,7 @@ void main() {
const ClearAttachmentPayload& clearPayload) { const ClearAttachmentPayload& clearPayload) {
m_clearManager->CollectGarbage(); m_clearManager->CollectGarbage();
// GL 3.3 §3.1: when RASTERIZER_DISCARD is enabled, Clear and ClearBuffer* are ignored. // GL 3.3 §3.1: when RASTERIZER_DISCARD is enabled, Clear and ClearBuffer* are ignored.
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) { if (MGB_CTX->IsCapabilityEnabled(CapabilityInput::RasterizerDiscard)) {
return; return;
} }
if (IsUnsupportedFramebufferForDirectVulkan(framebuffer)) { if (IsUnsupportedFramebufferForDirectVulkan(framebuffer)) {
@@ -7478,7 +7479,7 @@ void main() {
} }
// GL 3.3 §4.2.3: ClearBuffer* is clipped by GL_SCISSOR_TEST exactly like Clear. // GL 3.3 §4.2.3: ClearBuffer* is clipped by GL_SCISSOR_TEST exactly like Clear.
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest)) { if (MGB_CTX->IsCapabilityEnabled(CapabilityInput::ScissorTest)) {
VkClearRect clearRect{}; VkClearRect clearRect{};
switch (PrepareScissoredClear(framebuffer, clearRect)) { switch (PrepareScissoredClear(framebuffer, clearRect)) {
case ScissoredClearPrep::NoOp: case ScissoredClearPrep::NoOp:
@@ -7509,9 +7510,9 @@ void main() {
// GL 3.3 §4.2.3: ClearBuffer* honors the write masks like Clear. Deferred // GL 3.3 §4.2.3: ClearBuffer* honors the write masks like Clear. Deferred
// clears cannot express partial masks; warn and skip those. // clears cannot express partial masks; warn and skip those.
const auto depthClearAllowed = [&]() -> Bool { return MG_State::pGLContext->GetDepthMask(); }; const auto depthClearAllowed = [&]() -> Bool { return MGB_CTX->GetDepthMask(); };
const auto stencilClearAllowed = [&]() -> Bool { const auto stencilClearAllowed = [&]() -> Bool {
const Uint32 stencilWriteMask = MG_State::pGLContext->GetStencilState(StencilFace::Front).WriteMask; const Uint32 stencilWriteMask = MGB_CTX->GetStencilState(StencilFace::Front).WriteMask;
if ((stencilWriteMask & 0xFFu) == 0xFFu) { if ((stencilWriteMask & 0xFFu) == 0xFFu) {
return true; return true;
} }
@@ -7523,7 +7524,7 @@ void main() {
switch (buffer) { switch (buffer) {
case GL_COLOR: { case GL_COLOR: {
const BoolVec4 colorMask = MG_State::pGLContext->GetColorMaskIndexed(static_cast<Uint32>(drawbuffer)); const BoolVec4 colorMask = MGB_CTX->GetColorMaskIndexed(static_cast<Uint32>(drawbuffer));
if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) { if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) {
return; return;
} }
@@ -7580,7 +7581,7 @@ void main() {
if (!attachment.IsComplete()) { if (!attachment.IsComplete()) {
return; return;
} }
const BoolVec4 colorMask = MG_State::pGLContext->GetColorMaskIndexed(static_cast<Uint>(drawbuffer)); const BoolVec4 colorMask = MGB_CTX->GetColorMaskIndexed(static_cast<Uint>(drawbuffer));
if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) { if (!colorMask.r() && !colorMask.g() && !colorMask.b() && !colorMask.a()) {
return; return;
} }
@@ -7598,7 +7599,7 @@ void main() {
MakeVkClearColorValue(clearPayload, ColorFormatLacksAlpha(colorTexture)); MakeVkClearColorValue(clearPayload, ColorFormatLacksAlpha(colorTexture));
} else { } else {
VkImageAspectFlags aspects = 0; VkImageAspectFlags aspects = 0;
if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0 && MG_State::pGLContext->GetDepthMask() && if ((clearPayload.mask & GL_DEPTH_BUFFER_BIT) != 0 && MGB_CTX->GetDepthMask() &&
framebuffer.GetAttachment(FramebufferAttachmentType::Depth).IsComplete()) { framebuffer.GetAttachment(FramebufferAttachmentType::Depth).IsComplete()) {
aspects |= VK_IMAGE_ASPECT_DEPTH_BIT; aspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
} }
@@ -7606,7 +7607,7 @@ void main() {
framebuffer.GetAttachment(FramebufferAttachmentType::Stencil).IsComplete()) { framebuffer.GetAttachment(FramebufferAttachmentType::Stencil).IsComplete()) {
// GL 3.3 §4.2.3: the clear is masked by the front stencil write mask (see Clear). // GL 3.3 §4.2.3: the clear is masked by the front stencil write mask (see Clear).
const Uint32 stencilWriteMask = const Uint32 stencilWriteMask =
MG_State::pGLContext->GetStencilState(StencilFace::Front).WriteMask; MGB_CTX->GetStencilState(StencilFace::Front).WriteMask;
if ((stencilWriteMask & 0xFFu) == 0xFFu) { if ((stencilWriteMask & 0xFFu) == 0xFFu) {
aspects |= VK_IMAGE_ASPECT_STENCIL_BIT; aspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
} else if (stencilWriteMask != 0) { } else if (stencilWriteMask != 0) {
@@ -7625,7 +7626,7 @@ void main() {
void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer,
const ClearAttachmentPayload& clearPayload) { const ClearAttachmentPayload& clearPayload) {
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get(); auto* fbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
if (!fbo) { if (!fbo) {
return; return;
} }
@@ -8583,8 +8584,8 @@ void main() {
void VulkanRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, void VulkanRenderer::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) { GLbitfield mask, GLenum filter) {
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); auto readFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); auto drawFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
BlitNamedFramebuffer(readFbo, drawFbo, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); BlitNamedFramebuffer(readFbo, drawFbo, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
} }
@@ -8616,8 +8617,8 @@ void main() {
// The scissor test clips blit writes: intersect the destination rectangle with // The scissor test clips blit writes: intersect the destination rectangle with
// the scissor box and shrink the source proportionally. // the scissor box and shrink the source proportionally.
if (MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ScissorTest)) { if (MGB_CTX->IsCapabilityEnabled(CapabilityInput::ScissorTest)) {
const IntVec4& scissor = MG_State::pGLContext->GetScissorBox(); const IntVec4& scissor = MGB_CTX->GetScissorBox();
const auto clipAxis = [](GLint& d0, GLint& d1, GLint& s0, GLint& s1, GLint clipLo, GLint clipHi) -> Bool { const auto clipAxis = [](GLint& d0, GLint& d1, GLint& s0, GLint& s1, GLint clipLo, GLint clipHi) -> Bool {
const Bool dstFlipped = d1 < d0; const Bool dstFlipped = d1 < d0;
GLint lo = dstFlipped ? d1 : d0; GLint lo = dstFlipped ? d1 : d0;
@@ -9211,7 +9212,7 @@ void main() {
return; return;
} }
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); auto& textureUnit = MGB_CTX->GetTextureUnitObject(MGB_CTX->GetActiveTextureUnit());
auto destinationTexture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject(); auto destinationTexture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject();
if (destinationTexture == nullptr) { if (destinationTexture == nullptr) {
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation, RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
@@ -9219,7 +9220,7 @@ void main() {
return; return;
} }
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); auto readFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (readFbo == nullptr) { if (readFbo == nullptr) {
RecordTextureCopyError(__func__, ErrorCode::InvalidOperation, RecordTextureCopyError(__func__, ErrorCode::InvalidOperation,
"CopyTexSubImage2D requires a framebuffer bound to GL_READ_FRAMEBUFFER."); "CopyTexSubImage2D requires a framebuffer bound to GL_READ_FRAMEBUFFER.");
@@ -9930,7 +9931,7 @@ void main() {
return; return;
} }
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); auto readFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (readFbo == nullptr) { if (readFbo == nullptr) {
MGLOG_E_ONCE("DirectVulkan::ReadPixels skipped: no read framebuffer is bound"); MGLOG_E_ONCE("DirectVulkan::ReadPixels skipped: no read framebuffer is bound");
return; return;
@@ -10685,8 +10686,8 @@ void main() {
// Store honoring the client pack state (single slice). // Store honoring the client pack state (single slice).
const auto& pixelPackBufferObject = const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject(); MGB_CTX->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false); const auto packParams = MGB_CTX->GetPixelStoreParameters(false);
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width); const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
const SizeT packAlignment = packParams.Alignment > 0 ? static_cast<SizeT>(packParams.Alignment) : 1; const SizeT packAlignment = packParams.Alignment > 0 ? static_cast<SizeT>(packParams.Alignment) : 1;
const SizeT dstRowStride = ((rowPixels * dstPixelBytes) + packAlignment - 1) / packAlignment * packAlignment; const SizeT dstRowStride = ((rowPixels * dstPixelBytes) + packAlignment - 1) / packAlignment * packAlignment;
@@ -10716,7 +10717,7 @@ void main() {
void VulkanRenderer::GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) { void VulkanRenderer::GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target); const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); auto& activeUnit = MGB_CTX->GetTextureUnitObject(MGB_CTX->GetActiveTextureUnit());
auto textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject(); auto textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
GetTextureImage(textureObject, textureUploadTarget, level, format, type, -1, pixels); GetTextureImage(textureObject, textureUploadTarget, level, format, type, -1, pixels);
} }
@@ -10960,7 +10961,7 @@ void main() {
return; return;
} }
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); auto& textureUnit = MGB_CTX->GetTextureUnitObject(MGB_CTX->GetActiveTextureUnit());
auto texture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject(); auto texture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject();
MOBILEGL_ASSERT(texture != nullptr, "GenerateMipmap requires a bound texture."); MOBILEGL_ASSERT(texture != nullptr, "GenerateMipmap requires a bound texture.");
MOBILEGL_ASSERT(texture->IsComplete(), "GenerateMipmap requires a complete texture."); MOBILEGL_ASSERT(texture->IsComplete(), "GenerateMipmap requires a complete texture.");
@@ -11216,7 +11217,7 @@ void main() {
// resets its counter state, because those bytes describe the previous owner's span. // resets its counter state, because those bytes describe the previous owner's span.
Uint32 VulkanRenderer::CurrentXfbCounterSlot() { Uint32 VulkanRenderer::CurrentXfbCounterSlot() {
constexpr Uint32 kNoSlot = static_cast<Uint32>(kXfbCounterObjectSlots); constexpr Uint32 kNoSlot = static_cast<Uint32>(kXfbCounterObjectSlots);
const Uint64 identity = MG_State::pGLContext->GetBoundTransformFeedbackLifetimeId(); const Uint64 identity = MGB_CTX->GetBoundTransformFeedbackLifetimeId();
MOBILEGL_ASSERT(identity != 0, MOBILEGL_ASSERT(identity != 0,
"transform feedback object reported the free-slot sentinel (0) as its identity - " "transform feedback object reported the free-slot sentinel (0) as its identity - "
"every slot would then read as 'mine' without ever being claimed"); "every slot would then read as 'mine' without ever being claimed");
@@ -11233,7 +11234,7 @@ void main() {
Uint32 slot = freeSlot; Uint32 slot = freeSlot;
if (slot == kNoSlot) { if (slot == kNoSlot) {
for (Uint32 candidate = 0; candidate < kNoSlot; ++candidate) { for (Uint32 candidate = 0; candidate < kNoSlot; ++candidate) {
if (MG_State::pGLContext->HasOpenTransformFeedbackSpan(m_xfbCounterSlotOwner[candidate])) { if (MGB_CTX->HasOpenTransformFeedbackSpan(m_xfbCounterSlotOwner[candidate])) {
continue; continue;
} }
if (slot == kNoSlot || m_xfbCounterSlotLastUse[candidate] < m_xfbCounterSlotLastUse[slot]) { if (slot == kNoSlot || m_xfbCounterSlotLastUse[candidate] < m_xfbCounterSlotLastUse[slot]) {
@@ -11264,17 +11265,17 @@ void main() {
} }
Bool VulkanRenderer::BeginXfbCaptureForDraw(FrameContext::FrameData& frame) { Bool VulkanRenderer::BeginXfbCaptureForDraw(FrameContext::FrameData& frame) {
if (!m_transformFeedbackFeatureEnabled || MG_State::pGLContext == nullptr || if (!m_transformFeedbackFeatureEnabled || !MGB_CTX_LIVE ||
!MG_State::pGLContext->IsTransformFeedbackActive()) { !MGB_CTX->IsTransformFeedbackActive()) {
return false; return false;
} }
// A paused span captures nothing, and the counter buffers keep their values, so the // A paused span captures nothing, and the counter buffers keep their values, so the
// next resumed draw appends exactly where the last captured one stopped - which is // next resumed draw appends exactly where the last captured one stopped - which is
// what pause/resume means (ARB_transform_feedback2). // what pause/resume means (ARB_transform_feedback2).
if (MG_State::pGLContext->IsTransformFeedbackPaused()) { if (MGB_CTX->IsTransformFeedbackPaused()) {
return false; return false;
} }
const auto& program = MG_State::pGLContext->GetTransformFeedbackProgram(); const auto& program = MGB_CTX->GetTransformFeedbackProgram();
if (!program || program->GetTransformFeedbackVaryingCount() == 0) { if (!program || program->GetTransformFeedbackVaryingCount() == 0) {
return false; return false;
} }
@@ -11313,7 +11314,7 @@ void main() {
VkDeviceSize offsets[4] = {}; VkDeviceSize offsets[4] = {};
VkDeviceSize sizes[4] = {}; VkDeviceSize sizes[4] = {};
for (SizeT i = 0; i < bufferCount; ++i) { for (SizeT i = 0; i < bufferCount; ++i) {
auto& point = MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::TransformFeedback, auto& point = MGB_CTX->GetBufferBindingPoint(BufferTarget::TransformFeedback,
static_cast<Uint>(i)); static_cast<Uint>(i));
const auto& bufferObject = point.GetBoundObject(); const auto& bufferObject = point.GetBoundObject();
if (bufferObject == nullptr) { if (bufferObject == nullptr) {
@@ -11344,7 +11345,7 @@ void main() {
offsets, sizes); offsets, sizes);
const Uint32 counterSlot = CurrentXfbCounterSlot(); const Uint32 counterSlot = CurrentXfbCounterSlot();
const Uint64 generation = MG_State::pGLContext->GetTransformFeedbackGeneration(); const Uint64 generation = MGB_CTX->GetTransformFeedbackGeneration();
const Bool resume = m_xfbCountersValid[counterSlot] && m_xfbLastSeenGeneration[counterSlot] == generation; const Bool resume = m_xfbCountersValid[counterSlot] && m_xfbLastSeenGeneration[counterSlot] == generation;
m_xfbLastSeenGeneration[counterSlot] = generation; m_xfbLastSeenGeneration[counterSlot] = generation;
@@ -11367,7 +11368,7 @@ void main() {
if (!began) { if (!began) {
return; return;
} }
const auto& program = MG_State::pGLContext->GetTransformFeedbackProgram(); const auto& program = MGB_CTX->GetTransformFeedbackProgram();
const SizeT bufferCount = program ? std::min<SizeT>(program->GetTransformFeedbackBufferCount(), 4) : 0; const SizeT bufferCount = program ? std::min<SizeT>(program->GetTransformFeedbackBufferCount(), 4) : 0;
const Uint32 counterSlot = CurrentXfbCounterSlot(); const Uint32 counterSlot = CurrentXfbCounterSlot();
VkBuffer counterBuffers[4] = {}; VkBuffer counterBuffers[4] = {};
@@ -12015,7 +12016,7 @@ void main() {
default: break; default: break;
} }
if (mergeGranularity != 0) { if (mergeGranularity != 0) {
const RenderStateParameters& rsp = MG_State::pGLContext->GetRenderStateParameters(); const RenderStateParameters& rsp = MGB_CTX->GetRenderStateParameters();
if (rsp.PrimitiveRestartEnabled || rsp.PrimitiveRestartFixedIndexEnabled) { if (rsp.PrimitiveRestartEnabled || rsp.PrimitiveRestartFixedIndexEnabled) {
mergeGranularity = 0; mergeGranularity = 0;
} }
@@ -12093,7 +12094,7 @@ void main() {
return; return;
} }
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get(); const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get();
if (!indexBuffer) { if (!indexBuffer) {
MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: no element array buffer is bound"); MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: no element array buffer is bound");
@@ -12103,13 +12104,13 @@ void main() {
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect); const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset + const SizeT commandBytes = commandOffset +
static_cast<SizeT>(stride) * static_cast<SizeT>(maxdrawcount - 1) + kGLDrawElementsIndirectCommandBytes; static_cast<SizeT>(stride) * static_cast<SizeT>(maxdrawcount - 1) + kGLDrawElementsIndirectCommandBytes;
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (!drawBuffer || commandBytes > drawBuffer->GetSize()) { if (!drawBuffer || commandBytes > drawBuffer->GetSize()) {
MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range"); MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return; return;
} }
auto parameterBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject(); auto parameterBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
if (!parameterBuffer || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterBuffer->GetSize()) { if (!parameterBuffer || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterBuffer->GetSize()) {
MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range"); MGLOG_E_ONCE("MultiDrawElementsIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range");
return; return;
@@ -12194,7 +12195,7 @@ void main() {
return; return;
} }
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray(); const auto& vao = *MGB_CTX->GetBoundVertexArray();
const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get(); const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get();
if (!indexBuffer) { if (!indexBuffer) {
MGLOG_E_ONCE("MultiDrawElementsIndirect skipped: no element array buffer is bound"); MGLOG_E_ONCE("MultiDrawElementsIndirect skipped: no element array buffer is bound");
@@ -12204,7 +12205,7 @@ void main() {
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect); const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset + const SizeT commandBytes = commandOffset +
static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + kGLDrawElementsIndirectCommandBytes; static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + kGLDrawElementsIndirectCommandBytes;
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (!drawBuffer || commandBytes > drawBuffer->GetSize()) { if (!drawBuffer || commandBytes > drawBuffer->GetSize()) {
MGLOG_E_ONCE("MultiDrawElementsIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range"); MGLOG_E_ONCE("MultiDrawElementsIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return; return;
@@ -12274,7 +12275,7 @@ void main() {
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect); const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset + const SizeT commandBytes = commandOffset +
static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + kGLDrawArraysIndirectCommandBytes; static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) + kGLDrawArraysIndirectCommandBytes;
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject(); auto drawBuffer = MGB_CTX->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (!drawBuffer || commandBytes > drawBuffer->GetSize()) { if (!drawBuffer || commandBytes > drawBuffer->GetSize()) {
MGLOG_E_ONCE("MultiDrawArraysIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range"); MGLOG_E_ONCE("MultiDrawArraysIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return; return;
@@ -12763,8 +12764,8 @@ void main() {
if (!m_provokingVertexModePerPipeline) { if (!m_provokingVertexModePerPipeline) {
return VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; return VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
} }
return (MG_State::pGLContext != nullptr && return (MGB_CTX_LIVE &&
MG_State::pGLContext->GetProvokingVertexMode() == ProvokingVertexMode::FirstVertex) MGB_CTX->GetProvokingVertexMode() == ProvokingVertexMode::FirstVertex)
? VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT ? VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT
: VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT; : VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
} }