Merge remote-tracking branch 'origin/Feat/Backend-Direct-Vulkan' into Agent/CodexAudit

# Conflicts:
#	MobileGL/MG_Backend/BackendObject.h
#	MobileGL/MG_Backend/DirectGLES/Managers.cpp
#	MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp
#	MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp
#	MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp
#	MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp
#	MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp
#	MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp
#	MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp
#	MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp
#	MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h
#	MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp
#	MobileGL/MG_Impl/GLImpl/Program/GL_Program.h
#	MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp
#	MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h
#	MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp
#	MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp
#	MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.h
#	MobileGL/MG_State/GLState/BufferState/BufferObject.cpp
#	MobileGL/MG_State/GLState/BufferState/BufferObject.h
#	MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp
#	MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h
This commit is contained in:
BZLZHH
2026-06-09 21:18:12 +08:00
75 changed files with 5818 additions and 674 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ project("MobileGL")
option(MOBILEGL_BUILD_TEST "Build MobileGL tests" ON ) option(MOBILEGL_BUILD_TEST "Build MobileGL tests" ON )
option(MOBILEGL_BUILD_BENCHMARK "Build MobileGL benchmarks" ON ) option(MOBILEGL_BUILD_BENCHMARK "Build MobileGL benchmarks" ON )
option(MOBILEGL_FORCE_RELEASE_OPT "Enable Release optimization flags in Debug build" OFF) option(MOBILEGL_FORCE_RELEASE_OPT "Enable Release optimization flags in Debug build" ON )
option(MOBILEGL_ENABLE_TRACY "Enable tracy for profiling" OFF) option(MOBILEGL_ENABLE_TRACY "Enable tracy for profiling" OFF)
if (ANDROID) if (ANDROID)
+1 -1
View File
@@ -14,7 +14,7 @@ namespace MobileGL::MG_Config {
inline const String ProjectName = "MobileGL"; inline const String ProjectName = "MobileGL";
inline const String CoreName = "MobileGL Core"; inline const String CoreName = "MobileGL Core";
inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)"; inline const String CoreVendor = "MobileGL-Dev (BZLZHH, Swung0x48, Tungsten)";
inline const Version CoreVersion = {26, 5, 0, "-dev", VersionType::Development}; inline const Version CoreVersion = {26, 6, 0, "-dev", VersionType::Development};
inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true}; inline const VersionStringFormatAttrib DefaultVersionStringFormatAttrib = {2, 2, 0, true, true};
inline const Uint64 CacheVersion = 0; inline const Uint64 CacheVersion = 0;
+27
View File
@@ -8,8 +8,14 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include "MG_State/GLState/TextureState/TextureEnum.h"
namespace MobileGL { namespace MobileGL {
namespace MG_State::GLState {
class FramebufferObject;
class ITextureObject;
}
enum class BackendType { enum class BackendType {
DirectGLES, DirectGLES,
DirectVulkan, DirectVulkan,
@@ -31,6 +37,10 @@ namespace MobileGL {
void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, void (*MultiDrawElementsIndirect)(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount,
GLsizei stride); GLsizei stride);
void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void (*MultiDrawArraysIndirect)(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void (*MultiDrawElementsIndirectCount)(GLenum mode, GLenum type, const void* indirect,
GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
void (*MultiDrawArraysIndirectCount)(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void (*DrawRangeElementsBaseVertex)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void (*DrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
@@ -54,8 +64,17 @@ namespace MobileGL {
void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value); void (*ClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value); void (*ClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint* value);
void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value); void (*ClearBufferiv)(GLenum buffer, GLint drawbuffer, const GLint* value);
void (*ClearNamedFramebufferfv)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
void (*BlitNamedFramebuffer)(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void (*CopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, void (*CopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
@@ -64,6 +83,9 @@ namespace MobileGL {
void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void (*ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels); void* 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);
void (*GetTextureImage)(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
GLsizei bufSize, GLvoid* pixels);
void (*DispatchCompute)(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void (*DispatchCompute)(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void (*DispatchComputeIndirect)(GLintptr indirect); void (*DispatchComputeIndirect)(GLintptr indirect);
void (*MemoryBarrier)(GLbitfield barriers); void (*MemoryBarrier)(GLbitfield barriers);
@@ -138,6 +160,11 @@ namespace MobileGL {
Float ViewportBoundsRangeMax = 0.0f; Float ViewportBoundsRangeMax = 0.0f;
Int ViewportSubpixelBits = 0; Int ViewportSubpixelBits = 0;
Bool SupportsWideLines = false; Bool SupportsWideLines = false;
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
Uint32 SubgroupSize = 0;
Uint32 SubgroupSupportedStages = 0;
Uint32 SubgroupSupportedFeatures = 0;
Bool SubgroupQuadOperationsInAllStages = false;
}; };
enum class WindowBackend { enum class WindowBackend {
@@ -140,7 +140,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader, V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store, E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object, E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture}, E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
E_GL_ARB_shader_draw_parameters},
.IsCompatibilityProfile = false // Is Compatibility Profile .IsCompatibilityProfile = false // Is Compatibility Profile
}, },
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability .StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
@@ -174,6 +177,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
funcsTable.GL.MultiDrawElements = MultiDrawElements; funcsTable.GL.MultiDrawElements = MultiDrawElements;
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex; funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect; funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect; funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex; funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
funcsTable.GL.DrawRangeElements = DrawRangeElements; funcsTable.GL.DrawRangeElements = DrawRangeElements;
@@ -205,7 +209,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
funcsTable.GL.ClearBufferfv = ClearBufferfv; funcsTable.GL.ClearBufferfv = ClearBufferfv;
funcsTable.GL.ClearBufferuiv = ClearBufferuiv; funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv; funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer; funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D; funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D; funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
funcsTable.GL.GenerateMipmap = GenerateMipmap; funcsTable.GL.GenerateMipmap = GenerateMipmap;
+233 -5
View File
@@ -21,6 +21,7 @@
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h> #include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h> #include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h> #include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
#include <MG_Util/Metrics/BufferMetrics.h>
#include <MG_Util/Texture/PixelStoreProcessor.h> #include <MG_Util/Texture/PixelStoreProcessor.h>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@@ -56,6 +57,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return a; return a;
} }
struct DrawElementsIndirectCommand {
Uint32 count = 0;
Uint32 instanceCount = 0;
Uint32 firstIndex = 0;
Int32 baseVertex = 0;
Uint32 baseInstance = 0;
};
namespace DebugImpl { namespace DebugImpl {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
void ErrorLopper::Loop(const std::function<void(GLenum)>& func) { void ErrorLopper::Loop(const std::function<void(GLenum)>& func) {
@@ -106,6 +115,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
namespace BufferImpl { namespace BufferImpl {
void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) { void CreateAndSyncBufferObject(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
bufferObject->MarkPersistentMappedRangeDirty();
if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return; if (!(bufferObject->GetChangeBits() & BufferChangeBits::DirtyBit)) return;
const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get()); const auto& backendBufferIt = g_backendBufferObjects.find(bufferObject.get());
@@ -702,6 +712,41 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void SyncAndBindFramebufferObject(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
FramebufferTarget target, Bool forceSync = false) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
if (!framebuffer || framebuffer == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO) {
g_GLESFuncs.glBindFramebuffer(target == FramebufferTarget::Draw ? GL_DRAW_FRAMEBUFFER : GL_READ_FRAMEBUFFER,
0);
return;
}
auto& registry = FramebufferImpl::g_backendFramebufferObjects;
const auto& backendFBOIt = registry.find(framebuffer.get());
const Bool exists = backendFBOIt != registry.end();
auto& backendObj = exists ? backendFBOIt->second : registry.GetOrCreate(framebuffer);
if (!exists) {
backendObj = MakeShared<FramebufferImpl::BackendFramebufferObject>();
}
if (forceSync) {
backendObj->InvalidateSyncedState();
}
backendObj->SyncToBackend(framebuffer, target);
backendObj->Bind(target);
}
void ForceBindCurrentFBO(FramebufferTarget target) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
auto& slot = MG_State::pGLContext->GetFramebufferBindingSlot(target);
SyncAndBindFramebufferObject(slot.GetBoundObject(), target);
FramebufferImpl::g_fboBindVersions[(SizeT)target] = slot.GetVersion();
}
void PrepareForDraw(DrawSyncBit syncBit) { void PrepareForDraw(DrawSyncBit syncBit) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -883,6 +928,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
} }
} }
void SetCurrentBaseInstance(Uint32 baseInstance) {
const auto& currentProgram = MG_State::pGLContext->GetCurrentProgram();
if (!currentProgram || !currentProgram->GetLinkStatus()) {
return;
}
const auto& backendProgramIt = PrgramImpl::g_backendProgramObjects.find(currentProgram.get());
if (backendProgramIt != PrgramImpl::g_backendProgramObjects.end()) {
backendProgramIt->second->SetBaseInstance(baseInstance);
}
}
void PrepareForCompute(Bool includeDispatchIndirectBuffer) { void PrepareForCompute(Bool includeDispatchIndirectBuffer) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND); ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
@@ -1009,14 +1065,127 @@ namespace MobileGL::MG_Backend::DirectGLES {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__); DebugImpl::OpenGLScopeMarker marker(__func__);
#endif #endif
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::IndirectBuffer; if (drawcount <= 0) {
return;
}
if (stride == 0) {
stride = sizeof(DrawElementsIndirectCommand);
}
if (stride < static_cast<GLsizei>(sizeof(DrawElementsIndirectCommand))) {
MGLOG_E("MultiDrawElementsIndirect skipped: stride %d is smaller than command size %zu",
stride, sizeof(DrawElementsIndirectCommand));
return;
}
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::IndirectBuffer | DrawSyncBit::Instancing;
PrepareForDraw(syncBit); PrepareForDraw(syncBit);
for (GLsizei i = 0; i < drawcount; ++i) { const SizeT indexSize = MG_Util::GetGLTypeSize(type);
const GLvoid* cmd = reinterpret_cast<const GLvoid*>(reinterpret_cast<const uint8_t*>(indirect) + if (indexSize == 0) {
i * (stride ? stride : sizeof(GLsizei) * 4)); MGLOG_E("MultiDrawElementsIndirect skipped: unsupported index type 0x%x", type);
g_GLESFuncs.glDrawElementsIndirect(mode, type, cmd); return;
} }
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (!drawBuffer) {
MGLOG_E("MultiDrawElementsIndirect skipped: no GL_DRAW_INDIRECT_BUFFER is bound");
return;
}
drawBuffer->MarkPersistentMappedRangeDirty();
const auto drawData = drawBuffer->GetDataReadOnly();
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset + static_cast<SizeT>(stride) * static_cast<SizeT>(drawcount - 1) +
sizeof(DrawElementsIndirectCommand);
if (!drawData || commandBytes > drawData->size()) {
MGLOG_E("MultiDrawElementsIndirect skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return;
}
for (GLsizei i = 0; i < drawcount; ++i) {
DrawElementsIndirectCommand cmd{};
std::memcpy(&cmd, drawData->data() + commandOffset + static_cast<SizeT>(i) * stride, sizeof(cmd));
if (cmd.count == 0 || cmd.instanceCount == 0) {
continue;
}
SetCurrentBaseInstance(cmd.baseInstance);
const auto indexByteOffset = static_cast<SizeT>(cmd.firstIndex) * indexSize;
g_GLESFuncs.glDrawElementsInstancedBaseVertex(
mode, static_cast<GLsizei>(cmd.count), type, reinterpret_cast<const GLvoid*>(indexByteOffset),
static_cast<GLsizei>(cmd.instanceCount), cmd.baseVertex);
}
SetCurrentBaseInstance(0);
}
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
if (maxdrawcount <= 0) {
return;
}
if (stride == 0) {
stride = sizeof(DrawElementsIndirectCommand);
}
if (stride < static_cast<GLsizei>(sizeof(DrawElementsIndirectCommand))) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: stride %d is smaller than command size %zu",
stride, sizeof(DrawElementsIndirectCommand));
return;
}
DrawSyncBit syncBit = DrawSyncBit::IndexBuffer | DrawSyncBit::IndirectBuffer | DrawSyncBit::Instancing;
PrepareForDraw(syncBit);
const SizeT indexSize = MG_Util::GetGLTypeSize(type);
if (indexSize == 0) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: unsupported index type 0x%x", type);
return;
}
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
auto parameterBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
if (!drawBuffer) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: no GL_DRAW_INDIRECT_BUFFER is bound");
return;
}
if (!parameterBuffer) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: no GL_PARAMETER_BUFFER is bound");
return;
}
drawBuffer->MarkPersistentMappedRangeDirty();
parameterBuffer->MarkPersistentMappedRangeDirty();
const auto drawData = drawBuffer->GetDataReadOnly();
const auto parameterData = parameterBuffer->GetDataReadOnly();
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset + static_cast<SizeT>(stride) * static_cast<SizeT>(maxdrawcount - 1) +
sizeof(DrawElementsIndirectCommand);
if (!drawData || commandBytes > drawData->size()) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return;
}
if (!parameterData || drawcount < 0 || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterData->size()) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range");
return;
}
Uint32 actualDrawCount = 0;
std::memcpy(&actualDrawCount, parameterData->data() + drawcount, sizeof(actualDrawCount));
actualDrawCount = std::min<Uint32>(actualDrawCount, static_cast<Uint32>(maxdrawcount));
for (Uint32 i = 0; i < actualDrawCount; ++i) {
DrawElementsIndirectCommand cmd{};
std::memcpy(&cmd, drawData->data() + commandOffset + static_cast<SizeT>(i) * stride, sizeof(cmd));
if (cmd.count == 0 || cmd.instanceCount == 0) {
continue;
}
SetCurrentBaseInstance(cmd.baseInstance);
const auto indexByteOffset = static_cast<SizeT>(cmd.firstIndex) * indexSize;
g_GLESFuncs.glDrawElementsInstancedBaseVertex(
mode, static_cast<GLsizei>(cmd.count), type, reinterpret_cast<const GLvoid*>(indexByteOffset),
static_cast<GLsizei>(cmd.instanceCount), cmd.baseVertex);
}
SetCurrentBaseInstance(0);
} }
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) { void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
@@ -1127,6 +1296,31 @@ namespace MobileGL::MG_Backend::DirectGLES {
}); });
} }
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
TextureImpl::SyncNeccessaryTextures();
RenderStateImpl::SyncRenderState();
SyncAndBindFramebufferObject(readFramebuffer, FramebufferTarget::Read, true);
SyncAndBindFramebufferObject(drawFramebuffer, FramebufferTarget::Draw, true);
MGLOG_D("ES %s(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)", __func__, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str());
g_GLESFuncs.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
ForceBindCurrentFBO(FramebufferTarget::Read);
ForceBindCurrentFBO(FramebufferTarget::Draw);
}
Bool UpdateTextureBindingAtTarget(GLenum target) { Bool UpdateTextureBindingAtTarget(GLenum target) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND); ZoneScopedNC(__func__, TRACY_ZONECOLOR_BACKEND);
@@ -1637,6 +1831,40 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glClearBufferuiv(buffer, drawbuffer, value); g_GLESFuncs.glClearBufferuiv(buffer, drawbuffer, value);
} }
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
TextureImpl::SyncNeccessaryTextures();
RenderStateImpl::SyncRenderState();
SyncAndBindFramebufferObject(framebuffer, FramebufferTarget::Draw, true);
g_GLESFuncs.glClearBufferfv(buffer, drawbuffer, value);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
ForceBindCurrentFBO(FramebufferTarget::Draw);
}
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
TextureImpl::SyncNeccessaryTextures();
RenderStateImpl::SyncRenderState();
SyncAndBindFramebufferObject(framebuffer, FramebufferTarget::Draw, true);
g_GLESFuncs.glClearBufferfi(buffer, drawbuffer, depth, stencil);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
ForceBindCurrentFBO(FramebufferTarget::Draw);
}
class TempPixelStoreParameterSync { class TempPixelStoreParameterSync {
public: public:
TempPixelStoreParameterSync(Bool isUnpack) : m_isUnpack(isUnpack) { TempPixelStoreParameterSync(Bool isUnpack) : m_isUnpack(isUnpack) {
@@ -8,6 +8,7 @@
#pragma once #pragma once
#include <Includes.h> #include <Includes.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
#include <MG_State/GLState/TextureState/TextureState.h> #include <MG_State/GLState/TextureState/TextureState.h>
#include <MG_State/GLState/SamplerState/SamplerObject.h> #include <MG_State/GLState/SamplerState/SamplerObject.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h> #include <MG_Util/BackendLoaders/OpenGL/Loader.h>
@@ -30,6 +31,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
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);
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);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
@@ -46,8 +49,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLuint baseinstance); GLuint baseinstance);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
void DrawArraysIndirect(GLenum mode, const void* indirect); void DrawArraysIndirect(GLenum mode, const void* indirect);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void 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);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
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,
+103 -8
View File
@@ -23,9 +23,11 @@
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h> #include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h> #include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h> #include <MG_State/GLState/FramebufferState/FramebufferObject.h>
#include <cctype>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true; constexpr Bool PREFER_MAP_BUFFER_RANGE_FOR_BUFFER_SYNC = true;
constexpr const char* BASE_INSTANCE_UNIFORM_NAME = "mg_BaseInstance";
static Uint ResolveBackendEsslVersion() { static Uint ResolveBackendEsslVersion() {
const auto& version = g_GLESCapabilities.GLESVersion; const auto& version = g_GLESCapabilities.GLESVersion;
@@ -38,6 +40,47 @@ namespace MobileGL::MG_Backend::DirectGLES {
return 300; return 300;
} }
String ReplaceIdentifier(String source, const String& from, const String& to) {
SizeT pos = 0;
while ((pos = source.find(from, pos)) != String::npos) {
const Bool leftIsIdent = pos > 0 &&
(std::isalnum(static_cast<unsigned char>(source[pos - 1])) || source[pos - 1] == '_');
const SizeT end = pos + from.size();
const Bool rightIsIdent = end < source.size() &&
(std::isalnum(static_cast<unsigned char>(source[end])) || source[end] == '_');
if (!leftIsIdent && !rightIsIdent) {
source.replace(pos, from.size(), to);
pos += to.size();
} else {
pos = end;
}
}
return source;
}
String InjectUniformAfterVersion(String source, const String& declaration) {
const SizeT versionPos = source.find("#version");
if (versionPos == String::npos) {
return declaration + "\n" + source;
}
const SizeT lineEnd = source.find('\n', versionPos);
if (lineEnd == String::npos) {
return source + "\n" + declaration + "\n";
}
source.insert(lineEnd + 1, declaration + "\n");
return source;
}
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType) {
if (shaderType != GL_VERTEX_SHADER || source.find("gl_BaseInstance") == String::npos) {
return source;
}
source = ReplaceIdentifier(std::move(source), "gl_BaseInstance", BASE_INSTANCE_UNIFORM_NAME);
return InjectUniformAfterVersion(std::move(source),
String("uniform highp int ") + BASE_INSTANCE_UNIFORM_NAME + ";");
}
namespace BufferImpl { namespace BufferImpl {
BackendBufferObject::BackendBufferObject() { BackendBufferObject::BackendBufferObject() {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -646,13 +689,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get()); static_cast<MG_State::GLState::TextureObjectBuffer*>(stateTextureObject.get());
auto& slot = textureBufferObject->GetBufferBindingSlot(); auto& slot = textureBufferObject->GetBufferBindingSlot();
auto& buffer = slot.GetBoundObject(); auto& buffer = slot.GetBoundObject();
if (!buffer) {
MGLOG_D("Texture buffer object with ID: %u has no bound buffer, skipping sync.",
stateTextureObject->GetExternalIndex());
return;
}
auto bufferIndex = buffer->GetExternalIndex(); auto bufferIndex = buffer->GetExternalIndex();
currentTextureInfo.bufferExternalIndex = bufferIndex; currentTextureInfo.bufferExternalIndex = bufferIndex;
Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo);
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture (tex buffer) "
"with ID: %u",
m_backendTextureId);
// Need to sync texture buffer if not synced yet // Need to sync texture buffer if not synced yet
auto& backendBuffers = BufferImpl::g_backendBufferObjects; auto& backendBuffers = BufferImpl::g_backendBufferObjects;
@@ -676,7 +721,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat, TextureImpl::GenerateTextureFormatInfo(textureBufferObject->GetFormat(), &glInternalFormat, &glFormat,
&glType); &glType);
g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); if (needsRegeneration) {
MGLOG_D("Texture state changed significantly or not initialized, regenerating texture buffer with "
"ID: %u, buffer ID: %u, buffer size: %zu, format: %s",
m_backendTextureId, backendId, buffer->GetSize(),
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str());
g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId);
DebugImpl::ErrorLopper::Loop(
[file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) {
MGLOG_D("%s(%s:%d) glTexBuffer(format=%s, buffer=%u) ES error: %s",
func, file, line, MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
backendId, MG_Util::ConvertGLEnumToString(err).c_str());
});
}
break; break;
} }
default: default:
@@ -765,7 +822,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapS, GL_TEXTURE_WRAP_S, WrapMode)
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapT, GL_TEXTURE_WRAP_T, WrapMode)
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode) if (SupportsWrapR(targetInternal)) {
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(wrapR, GL_TEXTURE_WRAP_R, WrapMode)
} else {
m_cacheSamplerParameters.wrapR = samplerParams.wrapR;
}
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareFunc, GL_TEXTURE_COMPARE_FUNC, CompareFunc)
SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode) SYNC_TEX_SAMPLER_PARAM_IF_CHANGED(compareMode, GL_TEXTURE_COMPARE_MODE, CompareMode)
if (m_cacheSamplerParameters.minLod != samplerParams.minLod) { if (m_cacheSamplerParameters.minLod != samplerParams.minLod) {
@@ -918,17 +979,37 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId); g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_backendFBOId);
} }
void BackendFramebufferObject::InvalidateSyncedState() {
std::fill(std::begin(m_frontendDrawBuffers), std::end(m_frontendDrawBuffers),
FramebufferAttachmentType::Unknown);
std::fill(std::begin(m_backendDrawBuffers), std::end(m_backendDrawBuffers), GL_NONE);
m_frontendReadBuffer = FramebufferAttachmentType::Unknown;
m_backendReadBuffer = GL_NONE;
std::fill(m_syncedFrontendAttachmentVersions.begin(), m_syncedFrontendAttachmentVersions.end(),
static_cast<Uint16>(~0u));
}
static Bool SyncAttachmentObject(GLenum glFBOTarget, static Bool SyncAttachmentObject(GLenum glFBOTarget,
const MG_State::GLState::FramebufferAttachmentObject& attachmentObject, const MG_State::GLState::FramebufferAttachmentObject& attachmentObject,
GLenum glBackendAttachment) { GLenum glBackendAttachment) {
if (attachmentObject.IsTexture()) { if (attachmentObject.IsTexture()) {
const auto& textureObject = attachmentObject.GetTexture(); const auto& textureObject = attachmentObject.GetTexture();
SharedPtr<TextureImpl::BackendTextureObject> backendTextureObject;
const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get()); const auto& backendTextureIt = TextureImpl::g_backendTextureObjects.find(textureObject.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) { if (backendTextureIt == TextureImpl::g_backendTextureObjects.end()) {
auto& backendTextureSlot = TextureImpl::g_backendTextureObjects.GetOrCreate(textureObject);
if (!backendTextureSlot) {
backendTextureSlot = MakeShared<TextureImpl::BackendTextureObject>();
}
backendTextureObject = backendTextureSlot;
} else {
backendTextureObject = backendTextureIt->second;
}
if (!backendTextureObject) {
MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__); MGLOG_E("%s: No backend texture found for FBO attachment, cannot bind texture.", __func__);
return false; return false;
} }
const auto& backendTextureObject = backendTextureIt->second; backendTextureObject->SyncMipmapsToBackend(textureObject);
auto glTextureTarget = auto glTextureTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget()); MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget());
if (glTextureTarget == GL_UNKNOWN_MGL) { if (glTextureTarget == GL_UNKNOWN_MGL) {
@@ -1040,8 +1121,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
// relevant FRONTEND!!! version should be checked and updated // relevant FRONTEND!!! version should be checked and updated
if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) { if (m_syncedFrontendAttachmentVersions[i] != attachmentVersions[i]) {
SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment); if (SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment)) {
m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i]; m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i];
}
} }
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG
else { else {
@@ -1053,6 +1135,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(), MG_Util::ConvertFramebufferAttachmentTypeToString(frontendType).c_str(),
MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(), MG_Util::ConvertGLEnumToString(glBackendAttachment).c_str(),
m_syncedFrontendAttachmentVersions[i]); m_syncedFrontendAttachmentVersions[i]);
if (!attachmentObject.IsTexture() && !attachmentObject.IsRenderbuffer()) {
continue;
}
GLint objectType = GL_NONE; GLint objectType = GL_NONE;
g_GLESFuncs.glGetFramebufferAttachmentParameteriv( g_GLESFuncs.glGetFramebufferAttachmentParameteriv(
glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType); glFBOTarget, glBackendAttachment, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
@@ -1237,6 +1322,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
source = RemoveLayoutBinding(source); source = RemoveLayoutBinding(source);
source = ProcessOutColorLocations(source); source = ProcessOutColorLocations(source);
source = ForceFlatIntegerVaryings(source, glShaderType); source = ForceFlatIntegerVaryings(source, glShaderType);
source = EmulateBaseInstanceInVertexShader(std::move(source), glShaderType);
source = ForceSupporterOutput(source); source = ForceSupporterOutput(source);
// Patch for Photon compiler precision issue // Patch for Photon compiler precision issue
@@ -1287,6 +1373,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
} else { } else {
MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId); MGLOG_D("Program linked successfully. ID: %u", m_backendProgramId);
} }
m_baseInstanceUniformLocation = g_GLESFuncs.glGetUniformLocation(m_backendProgramId,
BASE_INSTANCE_UNIFORM_NAME);
// Create global UBO // Create global UBO
if (stateProgramObject->GetUBOSize() > 0) { if (stateProgramObject->GetUBOSize() > 0) {
@@ -1309,6 +1397,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_D("Using program %u", m_backendProgramId); MGLOG_D("Using program %u", m_backendProgramId);
g_GLESFuncs.glUseProgram(m_backendProgramId); g_GLESFuncs.glUseProgram(m_backendProgramId);
} }
void BackendProgramObjectImpl::SetBaseInstance(Uint32 baseInstance) const {
if (m_baseInstanceUniformLocation < 0) {
return;
}
g_GLESFuncs.glUniform1i(m_baseInstanceUniformLocation, static_cast<GLint>(baseInstance));
}
} // namespace PrgramImpl } // namespace PrgramImpl
namespace SamplerImpl { namespace SamplerImpl {
@@ -15,6 +15,8 @@
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
namespace MobileGL::MG_Backend::DirectGLES { namespace MobileGL::MG_Backend::DirectGLES {
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType);
template <typename StateObject, typename BackendObject> template <typename StateObject, typename BackendObject>
class StateBackendObjectRegistry { class StateBackendObjectRegistry {
public: public:
@@ -166,6 +168,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
return true; return true;
} }
inline Bool SupportsWrapR(TextureTarget target) {
return target == TextureTarget::Texture3D || target == TextureTarget::TextureCubeMap;
}
struct StateTextureBasicInfo { // Used for tracking texture state changes struct StateTextureBasicInfo { // Used for tracking texture state changes
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown; TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
SizeT width = 0; SizeT width = 0;
@@ -222,6 +228,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
BackendFramebufferObject(); BackendFramebufferObject();
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject, void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
FramebufferTarget asTarget); FramebufferTarget asTarget);
void InvalidateSyncedState();
Uint GetBackendFramebufferId() const { return m_backendFBOId; } Uint GetBackendFramebufferId() const { return m_backendFBOId; }
void Bind(FramebufferTarget target) const; void Bind(FramebufferTarget target) const;
// FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index); // FramebufferAttachmentType GetCompactedAttachmentTypeAtDrawBufferIndex(Int index);
@@ -263,12 +270,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
~BackendProgramObjectImpl(); ~BackendProgramObjectImpl();
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject); void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
void Use() const; void Use() const;
void SetBaseInstance(Uint32 baseInstance) const;
Uint GetBackendProgramId() const { return m_backendProgramId; } Uint GetBackendProgramId() const { return m_backendProgramId; }
Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; } Uint GetBackendGlobalUBOId() const { return m_backendGlobalUBOId; }
private: private:
Uint m_backendProgramId = 0; Uint m_backendProgramId = 0;
Uint m_backendGlobalUBOId = 0; Uint m_backendGlobalUBOId = 0;
Int m_baseInstanceUniformLocation = -1;
Bool m_isInitialized = false; Bool m_isInitialized = false;
}; };
@@ -19,6 +19,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default; BackendObject_DirectVulkan::~BackendObject_DirectVulkan() = default;
BackendObject_DirectVulkan::BackendObject_DirectVulkan():
m_rendererInfo{
.RendererName = "Magma",
.BackendName = "Direct (Vulkan)",
.ExtraVendor = Nullopt,
.RendererGLInfo =
{
.TargetGLVersion = {3, 3, 0},
.TargetGLSLVersion = {4, 6, 0},
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32,
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
E_GL_ARB_multi_draw_indirect, E_GL_ARB_indirect_parameters,
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture, E_GL_ARB_buffer_storage,
E_GL_ARB_texture_storage, E_GL_ARB_direct_state_access,
E_GL_ARB_shader_draw_parameters, E_GL_ARB_gpu_shader_int64},
.IsCompatibilityProfile = false
},
.StaticBackendCapability = {.AllowVSOnlyPrograms = false}} {}
Bool BackendObject_DirectVulkan::InitWindowSurface() { Bool BackendObject_DirectVulkan::InitWindowSurface() {
if (!m_windowHandle.Handle) { if (!m_windowHandle.Handle) {
MGLOG_E("Cannot initialize DirectVulkan window surface: native window handle is null"); MGLOG_E("Cannot initialize DirectVulkan window surface: native window handle is null");
@@ -47,8 +68,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetPhysicalDevice().properties); const auto& physicalDevice = pVulkanRenderer->GetPhysicalDevice();
if (!MG_Util::BackendLoader::QueryVulkanCapabilities(m_vulkanCaps, pVulkanRenderer->GetInstance(),
physicalDevice.handle)) {
MGLOG_W("DirectVulkan: failed to query extended Vulkan capabilities, using basic properties");
MG_Util::BackendLoader::FillInVulkanCapabilities(m_vulkanCaps, physicalDevice.properties);
}
UpdateDynamicBackendParameters(); UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions();
return true; return true;
} }
@@ -113,24 +140,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const { const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const {
static RendererInfo RendererInfo = { return m_rendererInfo;
.RendererName = "Magma", // Renderer Name
.BackendName = "Direct (Vulkan)", // Backend Name
.ExtraVendor = Nullopt, // Extra vendor
.RendererGLInfo =
{
.TargetGLVersion = {3, 3, 0}, // Target OpenGL Version
.TargetGLSLVersion = {4, 6, 0}, // Target Shading Language Version
.Extensions = {V_OpenGL30, V_OpenGL31, V_OpenGL32, // OpenGL Extensions
V_OpenGL33, E_GL_ARB_draw_buffers_blend, E_GL_ARB_compute_shader,
E_GL_ARB_shader_storage_buffer_object, E_GL_ARB_shader_image_load_store,
E_GL_ARB_program_interface_query, E_GL_ARB_framebuffer_object,
E_GL_EXT_framebuffer_object, E_GL_ARB_depth_texture},
.IsCompatibilityProfile = false // Is Compatibility Profile
},
.StaticBackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability
};
return RendererInfo;
} }
String BackendObject_DirectVulkan::GetBackendAPIVersionString() const { String BackendObject_DirectVulkan::GetBackendAPIVersionString() const {
@@ -160,6 +170,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex; funcsTable.GL.MultiDrawElementsBaseVertex = MultiDrawElementsBaseVertex;
funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect; funcsTable.GL.MultiDrawElementsIndirect = MultiDrawElementsIndirect;
funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect; funcsTable.GL.MultiDrawArraysIndirect = MultiDrawArraysIndirect;
funcsTable.GL.MultiDrawElementsIndirectCount = MultiDrawElementsIndirectCount;
funcsTable.GL.MultiDrawArraysIndirectCount = MultiDrawArraysIndirectCount;
funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex; funcsTable.GL.DrawRangeElementsBaseVertex = DrawRangeElementsBaseVertex;
funcsTable.GL.DrawRangeElements = DrawRangeElements; funcsTable.GL.DrawRangeElements = DrawRangeElements;
funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance; funcsTable.GL.DrawElementsInstancedBaseVertexBaseInstance = DrawElementsInstancedBaseVertexBaseInstance;
@@ -175,12 +187,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
funcsTable.GL.ClearBufferfv = ClearBufferfv; funcsTable.GL.ClearBufferfv = ClearBufferfv;
funcsTable.GL.ClearBufferuiv = ClearBufferuiv; funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv; funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer; funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D; funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D; funcsTable.GL.CopyTexSubImage2D = CopyTexSubImage2D;
funcsTable.GL.GenerateMipmap = GenerateMipmap; funcsTable.GL.GenerateMipmap = GenerateMipmap;
funcsTable.GL.ReadPixels = ReadPixels; funcsTable.GL.ReadPixels = ReadPixels;
funcsTable.GL.GetTexImage = GetTexImage; funcsTable.GL.GetTexImage = GetTexImage;
funcsTable.GL.GetTextureImage = GetTextureImage;
funcsTable.GL.DispatchCompute = DispatchCompute; funcsTable.GL.DispatchCompute = DispatchCompute;
funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect; funcsTable.GL.DispatchComputeIndirect = DispatchComputeIndirect;
funcsTable.GL.MemoryBarrier = MemoryBarrier; funcsTable.GL.MemoryBarrier = MemoryBarrier;
@@ -205,7 +221,67 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return m_dynamicParameters; return m_dynamicParameters;
} }
void BackendObject_DirectVulkan::ApplyVulkanCapabilitiesForTesting(
const MG_External::VulkanCapabilities& capabilities) {
m_vulkanCaps = capabilities;
UpdateDynamicBackendParameters();
UpdateAdvertisedExtensions();
}
void BackendObject_DirectVulkan::UpdateAdvertisedExtensions() {
auto& extensions = m_rendererInfo.RendererGLInfo.Extensions;
extensions.erase(std::remove(extensions.begin(), extensions.end(), E_GL_KHR_shader_subgroup),
extensions.end());
if (m_vulkanCaps.SupportsShaderSubgroup) {
extensions.push_back(E_GL_KHR_shader_subgroup);
}
}
void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() { void BackendObject_DirectVulkan::UpdateDynamicBackendParameters() {
const auto mapShaderStages = [](Uint32 vkStages) {
Uint32 glStages = 0;
if ((vkStages & VK_SHADER_STAGE_VERTEX_BIT) != 0) glStages |= GL_VERTEX_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) glStages |= GL_TESS_CONTROL_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) {
glStages |= GL_TESS_EVALUATION_SHADER_BIT;
}
if ((vkStages & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) glStages |= GL_GEOMETRY_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_FRAGMENT_BIT) != 0) glStages |= GL_FRAGMENT_SHADER_BIT;
if ((vkStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0) glStages |= GL_COMPUTE_SHADER_BIT;
return glStages;
};
const auto mapSubgroupFeatures = [](Uint32 vkFeatures) {
Uint32 glFeatures = 0;
if ((vkFeatures & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_BASIC_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_VOTE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_VOTE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR;
}
if ((vkFeatures & VK_SUBGROUP_FEATURE_QUAD_BIT) != 0) {
glFeatures |= GL_SUBGROUP_FEATURE_QUAD_BIT_KHR;
}
return glFeatures;
};
static constexpr SizeT kMaxAdvertisedShaderStorageBlockSize = 512ull * 1024ull * 1024ull;
m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment; m_dynamicParameters.UniformBufferOffsetAlignment = m_vulkanCaps.UniformBufferOffsetAlignment;
m_dynamicParameters.AliasedLineWidthRangeMin = m_vulkanCaps.AliasedLineWidthRangeMin; m_dynamicParameters.AliasedLineWidthRangeMin = m_vulkanCaps.AliasedLineWidthRangeMin;
m_dynamicParameters.AliasedLineWidthRangeMax = m_vulkanCaps.AliasedLineWidthRangeMax; m_dynamicParameters.AliasedLineWidthRangeMax = m_vulkanCaps.AliasedLineWidthRangeMax;
@@ -255,5 +331,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_dynamicParameters.ViewportBoundsRangeMax = m_vulkanCaps.ViewportBoundsRangeMax; m_dynamicParameters.ViewportBoundsRangeMax = m_vulkanCaps.ViewportBoundsRangeMax;
m_dynamicParameters.ViewportSubpixelBits = m_vulkanCaps.ViewportSubpixelBits; m_dynamicParameters.ViewportSubpixelBits = m_vulkanCaps.ViewportSubpixelBits;
m_dynamicParameters.SupportsWideLines = m_vulkanCaps.SupportsWideLines; m_dynamicParameters.SupportsWideLines = m_vulkanCaps.SupportsWideLines;
m_dynamicParameters.MaxShaderStorageBlockSize =
std::min(m_vulkanCaps.MaxShaderStorageBlockSize, kMaxAdvertisedShaderStorageBlockSize);
if (m_vulkanCaps.SupportsShaderSubgroup) {
m_dynamicParameters.SubgroupSize = m_vulkanCaps.SubgroupSize;
m_dynamicParameters.SubgroupSupportedStages = mapShaderStages(m_vulkanCaps.SubgroupSupportedStages);
m_dynamicParameters.SubgroupSupportedFeatures = mapSubgroupFeatures(m_vulkanCaps.SubgroupSupportedOperations);
m_dynamicParameters.SubgroupQuadOperationsInAllStages = m_vulkanCaps.SubgroupQuadOperationsInAllStages;
} else {
m_dynamicParameters.SubgroupSize = 0;
m_dynamicParameters.SubgroupSupportedStages = 0;
m_dynamicParameters.SubgroupSupportedFeatures = 0;
m_dynamicParameters.SubgroupQuadOperationsInAllStages = false;
}
if (m_dynamicParameters.MaxShaderStorageBlockSize != m_vulkanCaps.MaxShaderStorageBlockSize) {
MGLOG_I("DirectVulkan: clamped GL_MAX_SHADER_STORAGE_BLOCK_SIZE from %zu to %zu",
m_vulkanCaps.MaxShaderStorageBlockSize,
m_dynamicParameters.MaxShaderStorageBlockSize);
}
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -14,6 +14,7 @@
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
class BackendObject_DirectVulkan : public BackendObject { class BackendObject_DirectVulkan : public BackendObject {
public: public:
BackendObject_DirectVulkan();
~BackendObject_DirectVulkan() override; ~BackendObject_DirectVulkan() override;
void Initialize() override; void Initialize() override;
@@ -30,12 +31,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const GlobalBackendFunctionsTable& GetBackendFunctions() const override; const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
const DynamicBackendParameters& GetDynamicParameters() const override; const DynamicBackendParameters& GetDynamicParameters() const override;
BackendType GetBackendType() const override; BackendType GetBackendType() const override;
void ApplyVulkanCapabilitiesForTesting(const MG_External::VulkanCapabilities& capabilities);
private: private:
void UpdateAdvertisedExtensions();
void UpdateDynamicBackendParameters(); void UpdateDynamicBackendParameters();
Bool m_initialized = false; Bool m_initialized = false;
DynamicBackendParameters m_dynamicParameters; DynamicBackendParameters m_dynamicParameters;
MG_External::VulkanCapabilities m_vulkanCaps; MG_External::VulkanCapabilities m_vulkanCaps;
RendererInfo m_rendererInfo;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -157,6 +157,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
StorageBlockResource block{}; StorageBlockResource block{};
block.name = blockName; block.name = blockName;
block.binding = binding->binding;
block.dataSize = static_cast<GLint>(binding->block.size); block.dataSize = static_cast<GLint>(binding->block.size);
const GLuint blockIndex = static_cast<GLuint>(cache.storageBlocks.size()); const GLuint blockIndex = static_cast<GLuint>(cache.storageBlocks.size());
AddBufferVariablesRecursive(binding->block, blockName, blockIndex, cache.bufferVariables, AddBufferVariablesRecursive(binding->block, blockName, blockIndex, cache.bufferVariables,
@@ -235,8 +236,38 @@ namespace MobileGL::MG_Backend::DirectVulkan {
pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value); pVulkanRenderer->ClearBufferiv(buffer, drawbuffer, value);
} }
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {} void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {} GLint drawbuffer, const GLfloat* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferfi called with null GL context");
pVulkanRenderer->ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
}
void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirect called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirect called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, 0, drawcount, stride);
}
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride) {
MGLOG_W("DirectVulkan::MultiDrawArraysIndirect is not implemented yet (drawcount=%d)", drawcount);
}
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::MultiDrawElementsIndirectCount called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::MultiDrawElementsIndirectCount called with null GL context");
pVulkanRenderer->MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
MGLOG_W("DirectVulkan::MultiDrawArraysIndirectCount is not implemented yet (maxdrawcount=%d)", maxdrawcount);
}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) {} const void* indices, GLint basevertex) {}
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {} void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices) {}
@@ -277,8 +308,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void DispatchComputeIndirect(GLintptr indirect) { void DispatchComputeIndirect(GLintptr indirect) {
MGLOG_W("DirectVulkan::DispatchComputeIndirect is not implemented yet (offset=%zu)", MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::DispatchComputeIndirect called with null VulkanRenderer");
static_cast<SizeT>(indirect)); MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::DispatchComputeIndirect called with null GL context");
pVulkanRenderer->DispatchComputeIndirect(indirect);
} }
void MemoryBarrier(GLbitfield barriers) { void MemoryBarrier(GLbitfield barriers) {
@@ -589,8 +621,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding; cache.storageBlocks[storageBlockIndex].binding = storageBlockBinding;
} }
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) {
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {} MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ReadPixels called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ReadPixels called with null GL context");
pVulkanRenderer->ReadPixels(x, y, width, height, format, type, pixels);
}
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTexImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTexImage called with null GL context");
pVulkanRenderer->GetTexImage(target, level, format, type, pixels);
}
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::GetTextureImage called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::GetTextureImage called with null GL context");
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");
@@ -713,6 +759,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); pVulkanRenderer->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
} }
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::BlitNamedFramebuffer called with null VulkanRenderer");
pVulkanRenderer->BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0,
dstY0, dstX1, dstY1, mask, filter);
}
void Present() { void Present() {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::Present called with null VulkanRenderer");
pVulkanRenderer->Present(); pVulkanRenderer->Present();
@@ -17,6 +17,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil);
void Clear(GLbitfield mask); void Clear(GLbitfield mask);
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);
void DrawArrays(GLenum mode, GLint first, GLsizei count); void DrawArrays(GLenum mode, GLint first, GLsizei count);
@@ -27,6 +31,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
GLsizei drawcount, const GLint* basevertex); GLsizei drawcount, const GLint* basevertex);
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);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
@@ -44,6 +52,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DrawArraysIndirect(GLenum mode, const void* indirect); void DrawArraysIndirect(GLenum mode, const void* indirect);
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);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
GLsizei height, GLint border); GLsizei height, GLint border);
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,
@@ -69,5 +82,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
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);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture, TextureUploadTarget uploadTarget,
GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid* pixels);
void Present(); void Present();
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -178,9 +178,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex]; packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
packet.commandBuffer = frame.commandBuffer; packet.commandBuffer = frame.commandBuffer;
packet.submitInfo.waitSemaphoreCount = 1; packet.submitInfo.waitSemaphoreCount = frame.imageAvailableSemaphoreConsumed ? 0U : 1U;
packet.submitInfo.pWaitSemaphores = &packet.waitSemaphore; packet.submitInfo.pWaitSemaphores = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitSemaphore;
packet.submitInfo.pWaitDstStageMask = &packet.waitDstStageMask; packet.submitInfo.pWaitDstStageMask = frame.imageAvailableSemaphoreConsumed ? nullptr : &packet.waitDstStageMask;
packet.submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U; packet.submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
packet.submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &packet.commandBuffer : nullptr; packet.submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &packet.commandBuffer : nullptr;
packet.submitInfo.signalSemaphoreCount = 1; packet.submitInfo.signalSemaphoreCount = 1;
@@ -218,6 +218,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return result; return result;
} }
frame.imageAvailableSemaphoreConsumed = false;
return vkResetFences(device, 1, &frame.imageInFlightFence); return vkResetFences(device, 1, &frame.imageInFlightFence);
} }
@@ -260,6 +261,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
frame.hasCommandBufferRecorded = false; frame.hasCommandBufferRecorded = false;
frame.isCommandRecording = false; frame.isCommandRecording = false;
frame.imageAvailableSemaphoreConsumed = false;
return VK_SUCCESS; return VK_SUCCESS;
} }
@@ -277,5 +279,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
frame.imageAvailableSemaphore = VK_NULL_HANDLE; frame.imageAvailableSemaphore = VK_NULL_HANDLE;
frame.isCommandRecording = false; frame.isCommandRecording = false;
frame.hasCommandBufferRecorded = false; frame.hasCommandBufferRecorded = false;
frame.imageAvailableSemaphoreConsumed = false;
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -35,6 +35,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFence imageInFlightFence = VK_NULL_HANDLE; VkFence imageInFlightFence = VK_NULL_HANDLE;
Bool isCommandRecording = false; Bool isCommandRecording = false;
Bool hasCommandBufferRecorded = false; Bool hasCommandBufferRecorded = false;
Bool imageAvailableSemaphoreConsumed = false;
}; };
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount); VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
@@ -994,16 +994,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding, String NormalizeDescriptorName(const SpvReflectDescriptorBinding& binding,
ProgramFactory::DescriptorBindingKind kind) { ProgramFactory::DescriptorBindingKind kind) {
const char* rawName = binding.name; const char* rawName = binding.name;
if (kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic && if ((kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic ||
kind == ProgramFactory::DescriptorBindingKind::StorageBuffer) &&
binding.type_description != nullptr && binding.type_description->type_name != nullptr) { binding.type_description != nullptr && binding.type_description->type_name != nullptr) {
rawName = binding.type_description->type_name; rawName = binding.type_description->type_name;
} }
MOBILEGL_ASSERT(rawName != nullptr && rawName[0] != '\0', String name = (rawName != nullptr) ? rawName : "";
"ProgramFactory: descriptor has empty name (spirvId=%u type=%d)", binding.spirv_id, if (name.empty()) {
static_cast<Int>(binding.descriptor_type)); name = std::format("__mg_unnamed_descriptor_set{}_binding{}_id{}", binding.set, binding.binding,
binding.spirv_id);
String name = rawName; MGLOG_W("ProgramFactory: descriptor has empty name; using generated name '%s' (type=%d)",
name.c_str(), static_cast<Int>(binding.descriptor_type));
}
if (kind == ProgramFactory::DescriptorBindingKind::CombinedImageSampler || if (kind == ProgramFactory::DescriptorBindingKind::CombinedImageSampler ||
kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer || kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer ||
kind == ProgramFactory::DescriptorBindingKind::StorageImage) { kind == ProgramFactory::DescriptorBindingKind::StorageImage) {
@@ -202,7 +202,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const MG_State::GLState::ProgramObject& program, const MG_State::GLState::ProgramObject& program,
const ProgramFactory::VkProgramObject& programObj, const ProgramFactory::VkProgramObject& programObj,
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const { Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
(void)commandBuffer;
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null"); MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null"); MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
MOBILEGL_ASSERT(binding < programObj.samplerNameByBinding.size(), MOBILEGL_ASSERT(binding < programObj.samplerNameByBinding.size(),
@@ -254,23 +253,31 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Int attachmentLevel = 0; Int attachmentLevel = 0;
if (drawFbo && if (drawFbo &&
FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) { FindFramebufferAttachmentForTexture(*drawFbo, *texture, attachmentType, attachmentLevel)) {
MOBILEGL_ASSERT(false, MGLOG_W("ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound "
"ResolveSamplerDescriptor: framebuffer feedback loop detected: textureId=%d is bound " "for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, "
"for sampling at binding=%u, but is also attached to drawFbo=%u as %s (level=%d, " "trackedLayout=%d)",
"trackedLayout=%d)", texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(),
texture->GetExternalIndex(), binding, drawFbo->GetExternalIndex(), MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(),
MG_Util::ConvertFramebufferAttachmentTypeToString(attachmentType).c_str(), attachmentLevel, static_cast<Int>(resource->layout));
attachmentLevel, static_cast<Int>(resource->layout));
} }
MOBILEGL_ASSERT(false, const Bool readyForSampling = m_textureManager->TransitionTextureForSampling(commandBuffer, *texture);
if (!readyForSampling) {
MGLOG_E("ResolveSamplerDescriptor: failed to transition textureId=%d for sampler binding=%u",
texture->GetExternalIndex(), binding);
return false;
}
resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
MOBILEGL_ASSERT(resource != nullptr,
"ResolveSamplerDescriptor: failed to resync textureId=%d after sampling transition",
texture->GetExternalIndex());
MOBILEGL_ASSERT(IsValidSampledImageLayout(resource->layout),
"ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u", "ResolveSamplerDescriptor: invalid sampled image layout=%d for textureId=%d, binding=%u",
static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding); static_cast<Int>(resource->layout), texture->GetExternalIndex(), binding);
return false;
} }
outImageInfo = { outImageInfo = {
.sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse, *texture), .sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse, *texture),
.imageView = resource->fullView, .imageView = resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView,
.imageLayout = resource->layout, .imageLayout = resource->layout,
}; };
if (ShouldDumpDescriptorStats()) { if (ShouldDumpDescriptorStats()) {
@@ -316,7 +323,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
*samplerBindingOverride.texture), *samplerBindingOverride.texture),
.imageView = samplerBindingOverride.imageView != VK_NULL_HANDLE ? .imageView = samplerBindingOverride.imageView != VK_NULL_HANDLE ?
samplerBindingOverride.imageView : samplerBindingOverride.imageView :
resource->fullView, (resource->sampledView != VK_NULL_HANDLE ? resource->sampledView : resource->fullView),
.imageLayout = resource->layout, .imageLayout = resource->layout,
}; };
return outImageInfo.sampler != VK_NULL_HANDLE; return outImageInfo.sampler != VK_NULL_HANDLE;
@@ -615,6 +622,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
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'",
frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str()); frontendBinding, program.GetUniformBlockName(static_cast<Uint32>(blockIndex)).c_str());
bufferObject->MarkPersistentMappedRangeDirty();
const auto bufferData = bufferObject->GetDataReadOnly(); const auto bufferData = bufferObject->GetDataReadOnly();
MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(), MOBILEGL_ASSERT(bufferData != nullptr && !bufferData->empty(),
@@ -67,7 +67,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
.allocator = m_initInfo.allocator, .allocator = m_initInfo.allocator,
.frameCount = m_initInfo.frameCount, .frameCount = m_initInfo.frameCount,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.memoryUsage = m_initInfo.transientMemoryUsage, .memoryUsage = m_initInfo.transientMemoryUsage,
.allocationFlags = m_initInfo.transientAllocationFlags, .allocationFlags = m_initInfo.transientAllocationFlags,
.minBufferSize = m_initInfo.minUploadBytes, .minBufferSize = m_initInfo.minUploadBytes,
@@ -86,6 +86,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const auto* bufferData = bufferObject->GetDataReadOnly().get(); const auto* bufferData = bufferObject->GetDataReadOnly().get();
MOBILEGL_ASSERT(bufferData != nullptr, "VkBufferManager::SyncResidentBuffer requires frontend buffer data"); MOBILEGL_ASSERT(bufferData != nullptr, "VkBufferManager::SyncResidentBuffer requires frontend buffer data");
bufferObject->MarkPersistentMappedRangeDirty();
const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize()); const VkDeviceSize bufferSize = static_cast<VkDeviceSize>(bufferObject->GetSize());
if (bufferSize == 0) { if (bufferSize == 0) {
@@ -200,7 +201,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
case BufferKind::TextureBuffer: case BufferKind::TextureBuffer:
return VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT; return VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
case BufferKind::ShaderStorage: case BufferKind::ShaderStorage:
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
case BufferKind::Indirect:
return VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
default: default:
return 0; return 0;
} }
@@ -21,6 +21,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uniform, Uniform,
TextureBuffer, TextureBuffer,
ShaderStorage, ShaderStorage,
Indirect,
}; };
struct VkBufferManagerInitInfo { struct VkBufferManagerInitInfo {
@@ -140,6 +140,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(size)); Memcpy(static_cast<Uint8*>(mapped) + offset, data, static_cast<SizeT>(size));
const VkResult flushResult = vmaFlushAllocation(m_allocator, m_allocation, offset, size);
if (flushResult != VK_SUCCESS) {
MGLOG_E("VkBufferObject::Upload failed: vmaFlushAllocation returned %d", flushResult);
if (!wasMapped) {
Unmap();
}
return false;
}
if (!wasMapped) { if (!wasMapped) {
Unmap(); Unmap();
} }
@@ -87,6 +87,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return texture; return texture;
} }
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil) {
DepthStencilAttachmentLoadInfo info{};
info.depthLoadOp = clearDepth
? VK_ATTACHMENT_LOAD_OP_CLEAR
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD);
info.stencilLoadOp = clearStencil
? VK_ATTACHMENT_LOAD_OP_CLEAR
: (trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD);
info.initialLayout =
(trackedLayout == VK_IMAGE_LAYOUT_UNDEFINED || (clearDepth && clearStencil)) ? VK_IMAGE_LAYOUT_UNDEFINED
: trackedLayout;
return info;
}
VkRenderPassManager::VkRenderPassManager(VkDevice device, VkRenderPassManager::VkRenderPassManager(VkDevice device,
const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager, const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager,
SwapchainObject& swapchainObject): SwapchainObject& swapchainObject):
@@ -426,27 +443,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
depthAttachmentDescription.format = depthTextureResource->format; depthAttachmentDescription.format = depthTextureResource->format;
} }
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachmentDescription.loadOp = clearDepth ? const auto loadInfo =
VK_ATTACHMENT_LOAD_OP_CLEAR : ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil);
VK_ATTACHMENT_LOAD_OP_LOAD; depthAttachmentDescription.loadOp = loadInfo.depthLoadOp;
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.stencilLoadOp = clearStencil ? depthAttachmentDescription.stencilLoadOp = loadInfo.stencilLoadOp;
VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) { depthAttachmentDescription.initialLayout = loadInfo.initialLayout;
if (!clearDepth) { if (trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED && (!clearDepth || !clearStencil)) {
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; MGLOG_W("GetOrCreateRenderPass: depth/stencil attachment textureId=%d starts with undefined layout "
} "and partial/no clear; using DONT_CARE for uncleared aspects",
if (!clearStencil) { texture.GetExternalIndex());
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
} }
depthAttachmentDescription.initialLayout =
(clearDepth && clearStencil) || trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED ?
VK_IMAGE_LAYOUT_UNDEFINED :
trackedDepthLayout;
if (hasClear) { if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo { pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = depthAttachmentIndex, .attachmentIndex = depthAttachmentIndex,
@@ -461,9 +470,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}); });
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex)); attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
} else { } else {
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED, MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
depthAttachmentDescription.loadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD", "GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
texture.GetExternalIndex()); texture.GetExternalIndex());
MOBILEGL_ASSERT(depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED ||
depthAttachmentDescription.stencilLoadOp != VK_ATTACHMENT_LOAD_OP_LOAD,
"GetOrCreateRenderPass: stencil attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
texture.GetExternalIndex());
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo { trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture, .target = TrackedAttachmentTarget::Texture,
.texture = &texture, .texture = &texture,
@@ -37,6 +37,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}; };
struct DepthStencilAttachmentLoadInfo {
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
};
DepthStencilAttachmentLoadInfo ResolveDepthStencilAttachmentLoadInfo(
VkImageLayout trackedLayout, Bool clearDepth, Bool clearStencil);
struct RenderPassEntry { struct RenderPassEntry {
static inline VkDevice s_device; static inline VkDevice s_device;
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch; static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
@@ -674,8 +674,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat()); const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(texture.GetFormat());
const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo); const VkComponentMapping sampledComponents = ResolveSampledViewComponents(texture, formatInfo);
perMipSampledView = CreateImageView(resource->image, resource->format, resource->aspect, resource->viewType, const VkImageAspectFlags sampledAspect = ResolveSampledImageViewAspectMask(resource->aspect);
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents); perMipSampledView = CreateImageView(resource->image, resource->format, sampledAspect, resource->viewType,
mipLevel, 1, 0, resource->arrayLayers, &sampledComponents);
if (perMipSampledView == VK_NULL_HANDLE) { if (perMipSampledView == VK_NULL_HANDLE) {
MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(), MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(),
mipLevel); mipLevel);
@@ -1067,6 +1068,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void VkTextureManager::DeferResourceRelease(TextureResource&& resource) { void VkTextureManager::DeferResourceRelease(TextureResource&& resource) {
if (resource.image == VK_NULL_HANDLE && resource.fullView == VK_NULL_HANDLE && if (resource.image == VK_NULL_HANDLE && resource.fullView == VK_NULL_HANDLE &&
resource.sampledView == VK_NULL_HANDLE &&
resource.perMipViews.empty() && resource.perMipSampledViews.empty()) { resource.perMipViews.empty() && resource.perMipSampledViews.empty()) {
return; return;
} }
@@ -1141,6 +1143,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const Bool needsRecreate = const Bool needsRecreate =
resource.fullView == VK_NULL_HANDLE || resource.fullView == VK_NULL_HANDLE ||
resource.sampledView == VK_NULL_HANDLE ||
resource.sampledBaseMipLevel != baseMipLevel || resource.sampledBaseMipLevel != baseMipLevel ||
resource.sampledLevelCount != levelCount || resource.sampledLevelCount != levelCount ||
resource.syncedTextureParamsVersion != texture.GetTextureParamsVersion(); resource.syncedTextureParamsVersion != texture.GetTextureParamsVersion();
@@ -1152,6 +1155,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
DeferViewRelease(resource.fullView); DeferViewRelease(resource.fullView);
resource.fullView = VK_NULL_HANDLE; resource.fullView = VK_NULL_HANDLE;
} }
if (resource.sampledView != VK_NULL_HANDLE) {
DeferViewRelease(resource.sampledView);
resource.sampledView = VK_NULL_HANDLE;
}
for (auto& sampledView : resource.perMipSampledViews) { for (auto& sampledView : resource.perMipSampledViews) {
if (sampledView != VK_NULL_HANDLE) { if (sampledView != VK_NULL_HANDLE) {
DeferViewRelease(sampledView); DeferViewRelease(sampledView);
@@ -1166,6 +1173,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (resource.fullView == VK_NULL_HANDLE) { if (resource.fullView == VK_NULL_HANDLE) {
return false; return false;
} }
const VkImageAspectFlags sampledAspect = ResolveSampledImageViewAspectMask(resource.aspect);
resource.sampledView = CreateImageView(resource.image, resource.format, sampledAspect, resource.viewType,
baseMipLevel, levelCount, 0, resource.arrayLayers, &sampledComponents);
if (resource.sampledView == VK_NULL_HANDLE) {
return false;
}
resource.sampledBaseMipLevel = baseMipLevel; resource.sampledBaseMipLevel = baseMipLevel;
resource.sampledLevelCount = levelCount; resource.sampledLevelCount = levelCount;
@@ -1496,4 +1509,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return VK_IMAGE_ASPECT_COLOR_BIT; return VK_IMAGE_ASPECT_COLOR_BIT;
} }
} }
VkImageAspectFlags VkTextureManager::ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect) {
if ((imageAspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
return VK_IMAGE_ASPECT_COLOR_BIT;
}
if ((imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
return VK_IMAGE_ASPECT_DEPTH_BIT;
}
if ((imageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
return VK_IMAGE_ASPECT_STENCIL_BIT;
}
return imageAspect;
}
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -58,6 +58,7 @@ public:
VkImage image = VK_NULL_HANDLE; VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr; VmaAllocation allocation = nullptr;
VkImageView fullView = VK_NULL_HANDLE; VkImageView fullView = VK_NULL_HANDLE;
VkImageView sampledView = VK_NULL_HANDLE;
Vector<VkImageView> perMipViews; Vector<VkImageView> perMipViews;
Vector<VkImageView> perMipSampledViews; Vector<VkImageView> perMipSampledViews;
UnorderedMap<AttachmentViewKey, VkImageView, AttachmentViewKeyHash> attachmentViews; UnorderedMap<AttachmentViewKey, VkImageView, AttachmentViewKeyHash> attachmentViews;
@@ -79,6 +80,7 @@ public:
std::swap(this->image, that.image); std::swap(this->image, that.image);
std::swap(this->allocation, that.allocation); std::swap(this->allocation, that.allocation);
std::swap(this->fullView, that.fullView); std::swap(this->fullView, that.fullView);
std::swap(this->sampledView, that.sampledView);
std::swap(this->perMipViews, that.perMipViews); std::swap(this->perMipViews, that.perMipViews);
std::swap(this->perMipSampledViews, that.perMipSampledViews); std::swap(this->perMipSampledViews, that.perMipSampledViews);
std::swap(this->attachmentViews, that.attachmentViews); std::swap(this->attachmentViews, that.attachmentViews);
@@ -99,6 +101,9 @@ public:
if (fullView != VK_NULL_HANDLE) { if (fullView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, fullView, nullptr); vkDestroyImageView(s_device, fullView, nullptr);
} }
if (sampledView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, sampledView, nullptr);
}
for (const auto attachmentView : perMipViews) { for (const auto attachmentView : perMipViews) {
if (attachmentView != VK_NULL_HANDLE) { if (attachmentView != VK_NULL_HANDLE) {
vkDestroyImageView(s_device, attachmentView, nullptr); vkDestroyImageView(s_device, attachmentView, nullptr);
@@ -118,6 +123,7 @@ public:
vmaDestroyImage(s_allocator, image, allocation); vmaDestroyImage(s_allocator, image, allocation);
} }
fullView = VK_NULL_HANDLE; fullView = VK_NULL_HANDLE;
sampledView = VK_NULL_HANDLE;
perMipViews.clear(); perMipViews.clear();
perMipSampledViews.clear(); perMipSampledViews.clear();
attachmentViews.clear(); attachmentViews.clear();
@@ -163,6 +169,8 @@ public:
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture); Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
Bool TransitionTextureForStorageImage(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture); Bool TransitionTextureForStorageImage(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
static VkImageAspectFlags ResolveSampledImageViewAspectMask(VkImageAspectFlags imageAspect);
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
@@ -1372,6 +1372,127 @@ void main() {
const char* value = std::getenv("MOBILEGL_PRESENT_STATS"); const char* value = std::getenv("MOBILEGL_PRESENT_STATS");
return value != nullptr && value[0] == '1' && value[1] == '\0'; return value != nullptr && value[0] == '1' && value[1] == '\0';
} }
static Bool IsBgraVkFormat(VkFormat format) {
switch (format) {
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SNORM:
case VK_FORMAT_B8G8R8A8_SRGB:
return true;
default:
return false;
}
}
static SizeT AlignPixelRow(SizeT rowBytes, Int alignment) {
const SizeT resolvedAlignment = static_cast<SizeT>(std::max(alignment, 1));
return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
}
static Int GetReadbackChannelCount(GLenum format) {
switch (format) {
case GL_RGB:
case GL_BGR:
return 3;
case GL_RGBA:
case GL_BGRA:
return 4;
default:
return 0;
}
}
static void StoreReadbackPixel(const Uint8* src, Bool srcIsBgra, GLenum dstFormat, Uint8* dst) {
const Uint8 r = srcIsBgra ? src[2] : src[0];
const Uint8 g = src[1];
const Uint8 b = srcIsBgra ? src[0] : src[2];
const Uint8 a = src[3];
switch (dstFormat) {
case GL_RGB:
dst[0] = r;
dst[1] = g;
dst[2] = b;
break;
case GL_BGR:
dst[0] = b;
dst[1] = g;
dst[2] = r;
break;
case GL_RGBA:
dst[0] = r;
dst[1] = g;
dst[2] = b;
dst[3] = a;
break;
case GL_BGRA:
dst[0] = b;
dst[1] = g;
dst[2] = r;
dst[3] = a;
break;
default:
break;
}
}
static Bool PackReadbackToClientOrPbo(const Uint8* srcPixels, VkFormat srcFormat, GLsizei width,
GLsizei height, GLenum format, GLenum type, void* pixels) {
if (width <= 0 || height <= 0) {
return true;
}
if (type != GL_UNSIGNED_BYTE) {
MGLOG_E("DirectVulkan readback skipped: unsupported type=0x%x", type);
return false;
}
const Int dstChannels = GetReadbackChannelCount(format);
if (dstChannels == 0) {
MGLOG_E("DirectVulkan readback skipped: unsupported format=0x%x", format);
return false;
}
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
const SizeT dstRowStride = AlignPixelRow(rowPixels * static_cast<SizeT>(dstChannels),
packParams.Alignment);
const SizeT dstOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) *
static_cast<SizeT>(dstChannels);
const SizeT packedSize = dstOffset +
(static_cast<SizeT>(height - 1) * dstRowStride) +
(static_cast<SizeT>(width) * static_cast<SizeT>(dstChannels));
Vector<Uint8> packed(packedSize, 0);
const Bool srcIsBgra = IsBgraVkFormat(srcFormat);
for (GLsizei row = 0; row < height; ++row) {
const Uint8* srcRow = srcPixels + static_cast<SizeT>(row) * static_cast<SizeT>(width) * 4;
Uint8* dstRow = packed.data() + dstOffset + static_cast<SizeT>(row) * dstRowStride;
for (GLsizei col = 0; col < width; ++col) {
StoreReadbackPixel(srcRow + static_cast<SizeT>(col) * 4,
srcIsBgra,
format,
dstRow + static_cast<SizeT>(col) * static_cast<SizeT>(dstChannels));
}
}
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
const SizeT pboOffset = reinterpret_cast<SizeT>(pixels);
if (pboOffset + packed.size() > pixelPackBufferObject->GetSize()) {
MGLOG_E("DirectVulkan readback skipped: pixel pack buffer is too small");
return false;
}
pixelPackBufferObject->UploadSubData({packed.data(), packed.size()}, pboOffset);
return true;
}
if (pixels != nullptr && !packed.empty()) {
Memcpy(pixels, packed.data(), packed.size());
}
return true;
}
} // namespace } // namespace
VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
@@ -1462,7 +1583,7 @@ void main() {
.minUploadBytes = 4 * 1024 * 1024, .minUploadBytes = 4 * 1024 * 1024,
.transientMemoryUsage = VMA_MEMORY_USAGE_AUTO, .transientMemoryUsage = VMA_MEMORY_USAGE_AUTO,
.transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT, .transientAllocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT,
.transientPersistentMapping = false, .transientPersistentMapping = true,
}); });
MOBILEGL_ASSERT(succeeded, "VkBufferManager initialization failed."); MOBILEGL_ASSERT(succeeded, "VkBufferManager initialization failed.");
m_textureManager = MakeUnique<VkTextureManager>(); m_textureManager = MakeUnique<VkTextureManager>();
@@ -1683,6 +1804,7 @@ void main() {
auto sourceBufferShared = MG_State::pGLContext->GetBufferObject(sourceBuffer->GetExternalIndex()); auto sourceBufferShared = MG_State::pGLContext->GetBufferObject(sourceBuffer->GetExternalIndex());
MOBILEGL_ASSERT(sourceBufferShared != nullptr, MOBILEGL_ASSERT(sourceBufferShared != nullptr,
"UploadAndBindVertexStreams failed to resolve shared source buffer"); "UploadAndBindVertexStreams failed to resolve shared source buffer");
sourceBufferShared->MarkPersistentMappedRangeDirty();
BufferSlice slice{}; BufferSlice slice{};
const Bool isDirty = (sourceBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit); const Bool isDirty = (sourceBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit);
const Uint64 changeSerial = sourceBufferShared->GetChangeSerial(); const Uint64 changeSerial = sourceBufferShared->GetChangeSerial();
@@ -1752,7 +1874,10 @@ void main() {
++syntheticBinding; ++syntheticBinding;
} }
vkCmdBindVertexBuffers(commandBuffer, 0, static_cast<Uint32>(bindingCount), vkBuffers.data(), vkOffsets.data()); if (bindingCount > 0) {
vkCmdBindVertexBuffers(commandBuffer, 0, static_cast<Uint32>(bindingCount), vkBuffers.data(),
vkOffsets.data());
}
return true; return true;
} }
@@ -1787,6 +1912,7 @@ void main() {
BufferSlice slice{}; BufferSlice slice{};
auto indexBufferShared = MG_State::pGLContext->GetBufferObject(indexBuffer->GetExternalIndex()); auto indexBufferShared = MG_State::pGLContext->GetBufferObject(indexBuffer->GetExternalIndex());
MOBILEGL_ASSERT(indexBufferShared != nullptr, "UploadAndBindIndexBuffer failed to resolve shared EBO"); MOBILEGL_ASSERT(indexBufferShared != nullptr, "UploadAndBindIndexBuffer failed to resolve shared EBO");
indexBufferShared->MarkPersistentMappedRangeDirty();
const Bool isDirty = (indexBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit); const Bool isDirty = (indexBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit);
const Uint64 changeSerial = indexBufferShared->GetChangeSerial(); const Uint64 changeSerial = indexBufferShared->GetChangeSerial();
const SizeT indexBufferSize = indexBufferShared->GetSize(); const SizeT indexBufferSize = indexBufferShared->GetSize();
@@ -2928,16 +3054,56 @@ void main() {
vkCmdDispatch(frame.commandBuffer, numGroupsX, numGroupsY, numGroupsZ); vkCmdDispatch(frame.commandBuffer, numGroupsX, numGroupsY, numGroupsZ);
} }
void VulkanRenderer::MemoryBarrier(GLbitfield barriers) { void VulkanRenderer::DispatchComputeIndirect(GLintptr indirect) {
m_textureManager->CollectGarbage();
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
ProgramFactory::CompileOptionFlags transformFlags = 0;
const auto& programObj = m_programFactory->GetOrCreateProgram(program, transformFlags);
if (!frame.isCommandRecording) { if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording(); m_frameContext.BeginCommandRecording();
m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex()); m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
} }
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) { if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
VkRenderPassManager::EndRenderPass(frame.commandBuffer); VkRenderPassManager::EndRenderPass(frame.commandBuffer);
} }
const VkPipeline pipeline = GetOrCreateComputePipeline(programObj);
if (pipeline == VK_NULL_HANDLE) {
MGLOG_E("DispatchComputeIndirect skipped: compute pipeline creation failed for program=%u",
program.GetExternalIndex());
return;
}
vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
const Bool boundUniforms = m_uniformManager->BindProgramUniformBuffers(
frame.commandBuffer, program, programObj, m_frameContext.GetCurrentFrameIndex(),
VK_PIPELINE_BIND_POINT_COMPUTE);
if (!boundUniforms) {
MGLOG_E("DispatchComputeIndirect skipped: BindProgramUniformBuffers failed");
return;
}
auto indirectBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DispatchIndirect).GetBoundObject();
if (!indirectBuffer) {
MGLOG_E("DispatchComputeIndirect skipped: GL_DISPATCH_INDIRECT_BUFFER is not bound");
return;
}
indirectBuffer->MarkPersistentMappedRangeDirty();
BufferSlice slice{};
if (!m_bufferManager.SyncResidentBuffer(BufferKind::Indirect, indirectBuffer, slice)) {
MGLOG_E("DispatchComputeIndirect skipped: failed to sync indirect dispatch buffer");
return;
}
MGLOG_D("DirectVulkan: glDispatchComputeIndirect(offset=%zu)", static_cast<SizeT>(indirect));
vkCmdDispatchIndirect(frame.commandBuffer, slice.buffer, slice.offset + static_cast<VkDeviceSize>(indirect));
}
VkMemoryBarrier VulkanRenderer::BuildMemoryBarrierForGlBarriers(GLbitfield barriers) {
VkMemoryBarrier memoryBarrier{}; VkMemoryBarrier memoryBarrier{};
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.srcAccessMask = memoryBarrier.srcAccessMask =
@@ -2953,6 +3119,24 @@ void main() {
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
if ((barriers & GL_COMMAND_BARRIER_BIT) != 0) {
memoryBarrier.dstAccessMask |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
}
return memoryBarrier;
}
void VulkanRenderer::MemoryBarrier(GLbitfield barriers) {
auto& frame = m_frameContext.GetCurrent();
if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording();
m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
}
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
}
VkMemoryBarrier memoryBarrier = BuildMemoryBarrierForGlBarriers(barriers);
MGLOG_D("DirectVulkan: glMemoryBarrier(0x%x)", static_cast<Uint32>(barriers)); MGLOG_D("DirectVulkan: glMemoryBarrier(0x%x)", static_cast<Uint32>(barriers));
vkCmdPipelineBarrier(frame.commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, vkCmdPipelineBarrier(frame.commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
@@ -2976,12 +3160,11 @@ void main() {
m_clearManager->QueueClear(mask, payload, *fbo); m_clearManager->QueueClear(mask, payload, *fbo);
} }
void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, void VulkanRenderer::QueueClearBufferPayloadForFramebuffer(
const ClearAttachmentPayload& clearPayload) { const MG_State::GLState::FramebufferObject& framebuffer, GLenum buffer, GLint drawbuffer,
const ClearAttachmentPayload& clearPayload) {
m_clearManager->CollectGarbage(); m_clearManager->CollectGarbage();
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get(); if (IsUnsupportedFramebufferForDirectVulkan(framebuffer)) {
MOBILEGL_ASSERT(fbo, "VulkanRenderer::QueueClearBufferPayload: draw framebuffer not found");
if (IsUnsupportedFramebufferForDirectVulkan(*fbo)) {
RecordUnsupportedFramebufferError(__func__); RecordUnsupportedFramebufferError(__func__);
return; return;
} }
@@ -2990,7 +3173,7 @@ void main() {
if (attachmentType == FramebufferAttachmentType::None) { if (attachmentType == FramebufferAttachmentType::None) {
return; return;
} }
const auto& attachment = fbo->GetAttachment(attachmentType); const auto& attachment = framebuffer.GetAttachment(attachmentType);
if (!attachment.IsTexture() || attachment.IsRenderbuffer()) { if (!attachment.IsTexture() || attachment.IsRenderbuffer()) {
return; return;
} }
@@ -3004,7 +3187,7 @@ void main() {
RecordClearBufferError(__func__, ErrorCode::InvalidValue, "color drawbuffer index is out of range"); RecordClearBufferError(__func__, ErrorCode::InvalidValue, "color drawbuffer index is out of range");
return; return;
} }
queueAttachmentClear(fbo->GetDrawBuffers()[drawbuffer]); queueAttachmentClear(framebuffer.GetDrawBuffers()[drawbuffer]);
return; return;
} }
case GL_DEPTH: case GL_DEPTH:
@@ -3035,6 +3218,13 @@ void main() {
} }
} }
void VulkanRenderer::QueueClearBufferPayload(GLenum buffer, GLint drawbuffer,
const ClearAttachmentPayload& clearPayload) {
auto* fbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject().get();
MOBILEGL_ASSERT(fbo, "VulkanRenderer::QueueClearBufferPayload: draw framebuffer not found");
QueueClearBufferPayloadForFramebuffer(*fbo, buffer, drawbuffer, clearPayload);
}
void VulkanRenderer::ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { void VulkanRenderer::ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
ClearAttachmentPayload payload{}; ClearAttachmentPayload payload{};
payload.mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; payload.mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
@@ -3063,6 +3253,41 @@ void main() {
QueueClearBufferPayload(buffer, drawbuffer, payload); QueueClearBufferPayload(buffer, drawbuffer, payload);
} }
void VulkanRenderer::ClearNamedFramebufferfv(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer,
const GLfloat* value) {
if (!framebuffer || value == nullptr) {
return;
}
ClearAttachmentPayload payload{};
switch (buffer) {
case GL_COLOR:
payload.mask = GL_COLOR_BUFFER_BIT;
payload.color = FloatVec4(value[0], value[1], value[2], value[3]);
break;
case GL_DEPTH:
payload.mask = GL_DEPTH_BUFFER_BIT;
payload.depth = value[0];
break;
default:
break;
}
QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload);
}
void VulkanRenderer::ClearNamedFramebufferfi(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer,
GLfloat depth, GLint stencil) {
if (!framebuffer) {
return;
}
ClearAttachmentPayload payload{};
payload.mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
payload.depth = depth;
payload.stencil = static_cast<Uint32>(stencil);
QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload);
}
void VulkanRenderer::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { void VulkanRenderer::ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
if (value == nullptr) { if (value == nullptr) {
return; return;
@@ -3327,6 +3552,16 @@ 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 drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
BlitNamedFramebuffer(readFbo, drawFbo, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
void VulkanRenderer::BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFbo,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFbo,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) {
static constexpr GLbitfield kSupportedBlitMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; static constexpr GLbitfield kSupportedBlitMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
if ((mask & ~kSupportedBlitMask) != 0) { if ((mask & ~kSupportedBlitMask) != 0) {
MGLOG_E("BlitFramebuffer skipped: unsupported mask bits=0x%x", static_cast<Uint32>(mask)); MGLOG_E("BlitFramebuffer skipped: unsupported mask bits=0x%x", static_cast<Uint32>(mask));
@@ -3351,8 +3586,6 @@ void main() {
return; return;
} }
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
MOBILEGL_ASSERT(readFbo != nullptr, "VulkanRenderer::BlitFramebuffer: read framebuffer is null"); MOBILEGL_ASSERT(readFbo != nullptr, "VulkanRenderer::BlitFramebuffer: read framebuffer is null");
MOBILEGL_ASSERT(drawFbo != nullptr, "VulkanRenderer::BlitFramebuffer: draw framebuffer is null"); MOBILEGL_ASSERT(drawFbo != nullptr, "VulkanRenderer::BlitFramebuffer: draw framebuffer is null");
if (IsUnsupportedFramebufferForDirectVulkan(*readFbo) || if (IsUnsupportedFramebufferForDirectVulkan(*readFbo) ||
@@ -3656,10 +3889,18 @@ void main() {
MOBILEGL_ASSERT(ok, "%s: failed to restore source image layout", __func__); MOBILEGL_ASSERT(ok, "%s: failed to restore source image layout", __func__);
} }
if (!drawIsDefaultFbo) { VkPipelineStageFlags dstRestoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dstRestoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkAccessFlags dstRestoreAccessMask = 0;
VkAccessFlags dstRestoreAccessMask = 0; GetImageTransitionDestinationState(dstRestoreLayout, dstRestoreStageMask, dstRestoreAccessMask);
GetImageTransitionDestinationState(dstRestoreLayout, dstRestoreStageMask, dstRestoreAccessMask); if (drawIsDefaultFbo) {
VkImageLayout dstTrackedLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, dstBinding.image, dstTrackedLayout, dstRestoreLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, dstRestoreStageMask,
VK_ACCESS_TRANSFER_WRITE_BIT, dstRestoreAccessMask, dstBinding.aspectMask);
MOBILEGL_ASSERT(ok, "%s: failed to restore swapchain destination image layout", __func__);
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, dstTrackedLayout);
} else {
Bool ok = VkTextureManager::TransitionImageLayout( Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, dstRestoreLayout, frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, dstRestoreLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, dstRestoreStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, dstRestoreStageMask,
@@ -3855,6 +4096,287 @@ void main() {
MOBILEGL_ASSERT(dstRestored, "%s: failed to restore destination image layout", __func__); MOBILEGL_ASSERT(dstRestored, "%s: failed to restore destination image layout", __func__);
} }
Bool VulkanRenderer::SubmitReadbackCommandsAndWait(FrameContext::FrameData& frame) {
if (frame.isCommandRecording) {
m_frameContext.EndCommandRecording();
}
if (!frame.hasCommandBufferRecorded) {
return true;
}
VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo submitInfo{VK_STRUCTURE_TYPE_SUBMIT_INFO};
VkSemaphore waitSemaphore = frame.imageAvailableSemaphore;
if (!frame.imageAvailableSemaphoreConsumed) {
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &waitSemaphore;
submitInfo.pWaitDstStageMask = &waitDstStageMask;
}
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &frame.commandBuffer;
VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, frame.imageInFlightFence);
if (result != VK_SUCCESS) {
MGLOG_E("DirectVulkan readback: vkQueueSubmit returned %d", result);
return false;
}
frame.imageAvailableSemaphoreConsumed = true;
result = vkWaitForFences(m_device, 1, &frame.imageInFlightFence, VK_TRUE, UINT64_MAX);
if (result != VK_SUCCESS) {
MGLOG_E("DirectVulkan readback: vkWaitForFences returned %d", result);
return false;
}
result = vkResetFences(m_device, 1, &frame.imageInFlightFence);
if (result != VK_SUCCESS) {
MGLOG_E("DirectVulkan readback: vkResetFences returned %d", result);
return false;
}
frame.hasCommandBufferRecorded = false;
frame.isCommandRecording = false;
return true;
}
void VulkanRenderer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
void* pixels) {
if (width <= 0 || height <= 0) {
return;
}
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (readFbo == nullptr) {
MGLOG_E("DirectVulkan::ReadPixels skipped: no read framebuffer is bound");
return;
}
auto& frame = m_frameContext.GetCurrent();
if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording();
m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
}
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
}
const Bool readIsDefaultFbo =
(readFbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
BlitImageBinding srcBinding{};
if (!ResolveColorBlitBinding(*readFbo, true, m_imageIndexAcquired, m_swapchainObject, *m_textureManager,
srcBinding)) {
return;
}
if (!readIsDefaultFbo) {
const auto& sourceAttachment = readFbo->GetAttachment(readFbo->GetReadBuffer());
auto sourceTexture = sourceAttachment.GetTexture();
if (sourceTexture != nullptr) {
const Bool clearReady = MaterializePendingClearForTexture(frame.commandBuffer, *sourceTexture);
MOBILEGL_ASSERT(clearReady,
"ReadPixels: failed to materialize pending clear for source textureId=%d",
sourceTexture->GetExternalIndex());
}
}
const VkImageLayout srcOriginalLayout = readIsDefaultFbo
? m_swapchainObject.GetImageLayout(m_imageIndexAcquired)
: *srcBinding.trackedLayout;
if (srcOriginalLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
MGLOG_E("DirectVulkan::ReadPixels skipped: source image layout is undefined");
return;
}
const VkDeviceSize readbackSize = static_cast<VkDeviceSize>(width) * static_cast<VkDeviceSize>(height) * 4;
VkBufferObject readback;
if (!readback.Create({
.allocator = m_allocator,
.size = readbackSize,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
})) {
MGLOG_E("DirectVulkan::ReadPixels skipped: failed to create readback buffer");
return;
}
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkAccessFlags srcAccessMask = 0;
GetImageTransitionSourceState(srcOriginalLayout, srcStageMask, srcAccessMask);
if (readIsDefaultFbo) {
VkImageLayout trackedLayout = srcOriginalLayout;
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, srcBinding.image, trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask);
MOBILEGL_ASSERT(ok, "%s: failed to transition swapchain source image", __func__);
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, trackedLayout);
} else {
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask,
srcBinding.mipLevel, 1);
MOBILEGL_ASSERT(ok, "%s: failed to transition source image", __func__);
}
VkBufferImageCopy copyRegion{};
copyRegion.imageSubresource.aspectMask = srcBinding.aspectMask;
copyRegion.imageSubresource.mipLevel = srcBinding.mipLevel;
copyRegion.imageSubresource.baseArrayLayer = 0;
copyRegion.imageSubresource.layerCount = 1;
copyRegion.imageOffset = {x, y, 0};
copyRegion.imageExtent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
vkCmdCopyImageToBuffer(frame.commandBuffer, srcBinding.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
readback.GetHandle(), 1, &copyRegion);
VkPipelineStageFlags restoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkAccessFlags restoreAccessMask = 0;
GetImageTransitionDestinationState(srcOriginalLayout, restoreStageMask, restoreAccessMask);
if (readIsDefaultFbo) {
VkImageLayout trackedLayout = m_swapchainObject.GetImageLayout(m_imageIndexAcquired);
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, srcBinding.image, trackedLayout, srcOriginalLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, restoreStageMask,
VK_ACCESS_TRANSFER_READ_BIT, restoreAccessMask, srcBinding.aspectMask);
MOBILEGL_ASSERT(ok, "%s: failed to restore swapchain source image layout", __func__);
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, trackedLayout);
} else {
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, srcOriginalLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, restoreStageMask,
VK_ACCESS_TRANSFER_READ_BIT, restoreAccessMask, srcBinding.aspectMask,
srcBinding.mipLevel, 1);
MOBILEGL_ASSERT(ok, "%s: failed to restore source image layout", __func__);
}
if (!SubmitReadbackCommandsAndWait(frame)) {
return;
}
const auto* mapped = static_cast<const Uint8*>(readback.Map());
if (mapped == nullptr) {
MGLOG_E("DirectVulkan::ReadPixels skipped: failed to map readback buffer");
return;
}
const VkFormat srcFormat = readIsDefaultFbo ? m_swapchainObject.GetSurfaceFormat().format : VK_FORMAT_R8G8B8A8_UNORM;
PackReadbackToClientOrPbo(mapped, srcFormat, width, height, format, type, pixels);
}
void VulkanRenderer::GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
GetTextureImage(textureObject, textureUploadTarget, level, format, type, -1, pixels);
}
void VulkanRenderer::GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
TextureUploadTarget textureUploadTarget, GLint level, GLenum format,
GLenum type, GLsizei bufSize, GLvoid* pixels) {
if (textureObject == nullptr || textureObject->GetStorageType() != TextureStorageType::Mipmap) {
return;
}
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (level < 0 || static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
MGLOG_E("DirectVulkan::GetTexImage skipped: level %d is out of range", level);
return;
}
auto* resource = m_textureManager->SyncTextureAndGetDescriptor(*textureObject);
if (resource == nullptr || resource->image == VK_NULL_HANDLE) {
MGLOG_E("DirectVulkan::GetTexImage skipped: failed to sync textureId=%u",
textureObject->GetExternalIndex());
return;
}
if ((resource->aspect & VK_IMAGE_ASPECT_COLOR_BIT) == 0) {
MGLOG_E("DirectVulkan::GetTexImage skipped: only color textures are supported right now");
return;
}
auto& frame = m_frameContext.GetCurrent();
if (!frame.isCommandRecording) {
m_frameContext.BeginCommandRecording();
m_uniformManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
}
if (VkRenderPassManager::GetActiveRenderPass() != nullptr) {
VkRenderPassManager::EndRenderPass(frame.commandBuffer);
}
const Bool clearReady = MaterializePendingClearForTexture(frame.commandBuffer, *textureObject);
MOBILEGL_ASSERT(clearReady,
"GetTexImage: failed to materialize pending clear for textureId=%d",
textureObject->GetExternalIndex());
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, static_cast<Uint>(level));
const GLsizei width = texelSize.x();
const GLsizei height = texelSize.y();
if (width <= 0 || height <= 0) {
return;
}
if (bufSize >= 0) {
const Int dstChannels = GetReadbackChannelCount(format);
if (type == GL_UNSIGNED_BYTE && dstChannels > 0) {
const SizeT minSize = static_cast<SizeT>(width) * static_cast<SizeT>(height) *
static_cast<SizeT>(dstChannels);
if (static_cast<SizeT>(bufSize) < minSize) {
MGLOG_E("DirectVulkan::GetTextureImage skipped: destination buffer is too small");
return;
}
}
}
const VkDeviceSize readbackSize = static_cast<VkDeviceSize>(width) * static_cast<VkDeviceSize>(height) * 4;
VkBufferObject readback;
if (!readback.Create({
.allocator = m_allocator,
.size = readbackSize,
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.memoryUsage = VMA_MEMORY_USAGE_AUTO,
.allocationFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT,
})) {
MGLOG_E("DirectVulkan::GetTexImage skipped: failed to create readback buffer");
return;
}
const VkImageLayout originalLayout = resource->layout;
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkAccessFlags srcAccessMask = 0;
GetImageTransitionSourceState(originalLayout, srcStageMask, srcAccessMask);
Bool ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, resource->image, resource->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, resource->aspect,
static_cast<Uint32>(level), 1);
MOBILEGL_ASSERT(ok, "%s: failed to transition texture image", __func__);
VkBufferImageCopy copyRegion{};
copyRegion.imageSubresource.aspectMask = resource->aspect;
copyRegion.imageSubresource.mipLevel = static_cast<Uint32>(level);
copyRegion.imageSubresource.baseArrayLayer = 0;
copyRegion.imageSubresource.layerCount = 1;
copyRegion.imageExtent = {static_cast<Uint32>(width), static_cast<Uint32>(height), 1};
vkCmdCopyImageToBuffer(frame.commandBuffer, resource->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
readback.GetHandle(), 1, &copyRegion);
VkPipelineStageFlags restoreStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkAccessFlags restoreAccessMask = 0;
GetImageTransitionDestinationState(originalLayout, restoreStageMask, restoreAccessMask);
ok = VkTextureManager::TransitionImageLayout(
frame.commandBuffer, resource->image, resource->layout, originalLayout,
VK_PIPELINE_STAGE_TRANSFER_BIT, restoreStageMask,
VK_ACCESS_TRANSFER_READ_BIT, restoreAccessMask, resource->aspect,
static_cast<Uint32>(level), 1);
MOBILEGL_ASSERT(ok, "%s: failed to restore texture image layout", __func__);
if (!SubmitReadbackCommandsAndWait(frame)) {
return;
}
const auto* mapped = static_cast<const Uint8*>(readback.Map());
if (mapped == nullptr) {
MGLOG_E("DirectVulkan::GetTextureImage skipped: failed to map readback buffer");
return;
}
PackReadbackToClientOrPbo(mapped, resource->format, width, height, format, type, pixels);
}
void VulkanRenderer::GenerateMipmap(GLenum target) { void VulkanRenderer::GenerateMipmap(GLenum target) {
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
const auto uploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target); const auto uploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
@@ -4127,6 +4649,108 @@ void main() {
} }
} }
void VulkanRenderer::MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect,
GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) {
auto& frame = m_frameContext.GetCurrent();
if (maxdrawcount <= 0) {
return;
}
if (stride == 0) {
stride = sizeof(DrawIndexedCmdParam);
}
if (stride < static_cast<GLsizei>(sizeof(DrawIndexedCmdParam))) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: stride %d is smaller than command size %zu",
stride, sizeof(DrawIndexedCmdParam));
return;
}
const SizeT indexSize = MG_Util::GetGLTypeSize(type);
if (indexSize == 0) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: unsupported index type 0x%x", type);
return;
}
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
const auto* indexBuffer = vao.GetIndexBufferBindingSlot().GetBoundObject().get();
if (!indexBuffer) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: no element array buffer is bound");
return;
}
const SizeT commandOffset = reinterpret_cast<SizeT>(indirect);
const SizeT commandBytes = commandOffset +
static_cast<SizeT>(stride) * static_cast<SizeT>(maxdrawcount - 1) + sizeof(DrawIndexedCmdParam);
auto drawBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::DrawIndirect).GetBoundObject();
if (!drawBuffer || commandBytes > drawBuffer->GetSize()) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: invalid GL_DRAW_INDIRECT_BUFFER binding or range");
return;
}
auto parameterBuffer = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
if (!parameterBuffer || static_cast<SizeT>(drawcount) + sizeof(Uint32) > parameterBuffer->GetSize()) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: invalid GL_PARAMETER_BUFFER binding or range");
return;
}
DrawCmdParam vertexRange{};
vertexRange.vertexCount = static_cast<Uint32>(indexBuffer->GetSize() / indexSize);
vertexRange.instanceCount = 1;
IndexBufferView indexBufferView{};
indexBufferView.indexType = type;
indexBufferView.indexByteOffset = 0;
indexBufferView.indexByteSize = indexBuffer->GetSize();
if (!SetupDraw(frame, mode, DrawSetupAspect::IndexBuffer | DrawSetupAspect::IndirectDrawBuffer,
vertexRange, &indexBufferView)) {
return;
}
drawBuffer->MarkPersistentMappedRangeDirty();
parameterBuffer->MarkPersistentMappedRangeDirty();
BufferSlice drawSlice{};
if (!m_bufferManager.SyncResidentBuffer(BufferKind::Indirect, drawBuffer, drawSlice)) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: failed to sync draw indirect buffer");
return;
}
BufferSlice parameterSlice{};
if (!m_bufferManager.SyncResidentBuffer(BufferKind::Indirect, parameterBuffer, parameterSlice)) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: failed to sync parameter buffer");
return;
}
MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__);
if (m_drawIndirectCountExtensionEnabled && s_vkCmdDrawIndexedIndirectCount) {
MGLOG_D("DirectVulkan: glMultiDrawElementsIndirectCountARB(max=%d stride=%d)", maxdrawcount, stride);
s_vkCmdDrawIndexedIndirectCount(frame.commandBuffer,
drawSlice.buffer,
drawSlice.offset + static_cast<VkDeviceSize>(commandOffset),
parameterSlice.buffer,
parameterSlice.offset + static_cast<VkDeviceSize>(drawcount),
static_cast<Uint32>(maxdrawcount),
static_cast<Uint32>(stride));
return;
}
const auto parameterData = parameterBuffer->GetDataReadOnly();
const auto drawData = drawBuffer->GetDataReadOnly();
if (!parameterData || !drawData) {
MGLOG_E("MultiDrawElementsIndirectCount skipped: CPU fallback cannot read buffers");
return;
}
Uint32 actualDrawCount = 0;
std::memcpy(&actualDrawCount, parameterData->data() + drawcount, sizeof(actualDrawCount));
actualDrawCount = std::min<Uint32>(actualDrawCount, static_cast<Uint32>(maxdrawcount));
for (Uint32 idraw = 0; idraw < actualDrawCount; ++idraw) {
DrawIndexedCmdParam cmd{};
std::memcpy(&cmd, drawData->data() + commandOffset + static_cast<SizeT>(idraw) * stride, sizeof(cmd));
vkCmdDrawIndexed(frame.commandBuffer, cmd.indexCount, cmd.instanceCount, cmd.firstIndex,
cmd.vertexOffset, cmd.firstInstance);
}
}
void VulkanRenderer::Present() { void VulkanRenderer::Present() {
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(), MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
"Present, acquired image index out of range"); "Present, acquired image index out of range");
@@ -4558,6 +5182,9 @@ void main() {
deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance; deviceFeatures.shaderCullDistance = supportedDeviceFeatures.shaderCullDistance;
deviceFeatures.wideLines = supportedDeviceFeatures.wideLines; deviceFeatures.wideLines = supportedDeviceFeatures.wideLines;
m_logicOpFeatureEnabled = deviceFeatures.logicOp == VK_TRUE; m_logicOpFeatureEnabled = deviceFeatures.logicOp == VK_TRUE;
deviceFeatures.shaderInt64 = supportedDeviceFeatures.shaderInt64;
deviceFeatures.drawIndirectFirstInstance = supportedDeviceFeatures.drawIndirectFirstInstance;
m_logicOpFeatureEnabled = deviceFeatures.logicOp == VK_TRUE;
VkDeviceCreateInfo deviceCreateInfo{}; VkDeviceCreateInfo deviceCreateInfo{};
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
@@ -4622,20 +5249,26 @@ void main() {
deviceCreateInfo.enabledExtensionCount = static_cast<Uint32>(enabledDeviceExtensions.size()); deviceCreateInfo.enabledExtensionCount = static_cast<Uint32>(enabledDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data(); deviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.data();
MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s", MGLOG_I("Device feature support: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s "
"shaderCullDistance=%s wideLines=%s shaderInt64=%s drawIndirectFirstInstance=%s",
supportedDeviceFeatures.geometryShader ? "true" : "false", supportedDeviceFeatures.geometryShader ? "true" : "false",
supportedDeviceFeatures.independentBlend ? "true" : "false", supportedDeviceFeatures.independentBlend ? "true" : "false",
supportedDeviceFeatures.logicOp ? "true" : "false", supportedDeviceFeatures.logicOp ? "true" : "false",
supportedDeviceFeatures.shaderClipDistance ? "true" : "false", supportedDeviceFeatures.shaderClipDistance ? "true" : "false",
supportedDeviceFeatures.shaderCullDistance ? "true" : "false", supportedDeviceFeatures.shaderCullDistance ? "true" : "false",
supportedDeviceFeatures.wideLines ? "true" : "false"); supportedDeviceFeatures.wideLines ? "true" : "false",
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s shaderCullDistance=%s wideLines=%s", supportedDeviceFeatures.shaderInt64 ? "true" : "false",
supportedDeviceFeatures.drawIndirectFirstInstance ? "true" : "false");
MGLOG_I("Device feature enabled: geometryShader=%s independentBlend=%s logicOp=%s shaderClipDistance=%s "
"shaderCullDistance=%s wideLines=%s shaderInt64=%s drawIndirectFirstInstance=%s",
deviceFeatures.geometryShader ? "true" : "false", deviceFeatures.geometryShader ? "true" : "false",
deviceFeatures.independentBlend ? "true" : "false", deviceFeatures.independentBlend ? "true" : "false",
deviceFeatures.logicOp ? "true" : "false", deviceFeatures.logicOp ? "true" : "false",
deviceFeatures.shaderClipDistance ? "true" : "false", deviceFeatures.shaderClipDistance ? "true" : "false",
deviceFeatures.shaderCullDistance ? "true" : "false", deviceFeatures.shaderCullDistance ? "true" : "false",
deviceFeatures.wideLines ? "true" : "false"); deviceFeatures.wideLines ? "true" : "false",
deviceFeatures.shaderInt64 ? "true" : "false",
deviceFeatures.drawIndirectFirstInstance ? "true" : "false");
VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice"); VK_VERIFY(vkCreateDevice(m_physicalDevice.handle, &deviceCreateInfo, nullptr, &m_device), "vkCreateDevice");
s_vkCmdDrawIndexedIndirectCount = reinterpret_cast<PFNDrawIndexedIndirectCountFunc>( s_vkCmdDrawIndexedIndirectCount = reinterpret_cast<PFNDrawIndexedIndirectCountFunc>(
@@ -4842,6 +5475,8 @@ void main() {
Vector<const char*>& inOutEnabledExtensions) { Vector<const char*>& inOutEnabledExtensions) {
m_drawIndirectCountExtensionEnabled = EnableOptionalDeviceExtension(availableExtensions, inOutEnabledExtensions, m_drawIndirectCountExtensionEnabled = EnableOptionalDeviceExtension(availableExtensions, inOutEnabledExtensions,
VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME); VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
EnableOptionalDeviceExtension(availableExtensions, inOutEnabledExtensions,
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME #ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
EnableOptionalDeviceExtension(availableExtensions, inOutEnabledExtensions, EnableOptionalDeviceExtension(availableExtensions, inOutEnabledExtensions,
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
@@ -4918,6 +5553,10 @@ void main() {
return m_physicalDevice; return m_physicalDevice;
} }
VkInstance VulkanRenderer::GetInstance() const {
return m_instance;
}
Bool VulkanRenderer::IsDrawIndirectCountExtensionEnabled() const { Bool VulkanRenderer::IsDrawIndirectCountExtensionEnabled() const {
return m_drawIndirectCountExtensionEnabled; return m_drawIndirectCountExtensionEnabled;
} }
@@ -120,20 +120,39 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value); void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value); void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, void 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);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFbo,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFbo,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint x, GLint y, GLsizei width, GLsizei height); GLint x, GLint y, GLsizei width, GLsizei height);
void GenerateMipmap(GLenum target); void GenerateMipmap(GLenum target);
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void GetTextureImage(const SharedPtr<MG_State::GLState::ITextureObject>& texture,
TextureUploadTarget uploadTarget, GLint level, GLenum format, GLenum type,
GLsizei bufSize, GLvoid* pixels);
void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
void DispatchComputeIndirect(GLintptr indirect);
void MemoryBarrier(GLbitfield barriers); void MemoryBarrier(GLbitfield barriers);
static VkMemoryBarrier BuildMemoryBarrierForGlBarriers(GLbitfield barriers);
void DrawArrays(const DrawCmd& payload); void DrawArrays(const DrawCmd& payload);
void DrawElements(const DrawIndexedCmd& payload); void DrawElements(const DrawIndexedCmd& payload);
void MultiDrawElements(const MultiDrawIndexedCmd& payloads); void MultiDrawElements(const MultiDrawIndexedCmd& payloads);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void Present(); void Present();
const PhysicalDevice& GetPhysicalDevice() const; const PhysicalDevice& GetPhysicalDevice() const;
VkInstance GetInstance() const;
Bool IsDrawIndirectCountExtensionEnabled() const; Bool IsDrawIndirectCountExtensionEnabled() const;
void RecreateSwapchain(); void RecreateSwapchain();
@@ -173,6 +192,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}; };
void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload); void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload);
void QueueClearBufferPayloadForFramebuffer(const MG_State::GLState::FramebufferObject& framebuffer,
GLenum buffer, GLint drawbuffer,
const ClearAttachmentPayload& clearPayload);
NativeWindowType m_window = 0; NativeWindowType m_window = 0;
void* m_platformDisplay = nullptr; void* m_platformDisplay = nullptr;
@@ -280,6 +302,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const IntVec3& storageBaseTexelSize, const IntVec3& storageBaseTexelSize,
VkImageLayout originalLayout, VkImageLayout originalLayout,
VkImageLayout finalLayout); VkImageLayout finalLayout);
Bool SubmitReadbackCommandsAndWait(FrameContext::FrameData& frame);
void ShutdownSwapchain(); void ShutdownSwapchain();
File diff suppressed because it is too large Load Diff
@@ -20,6 +20,23 @@ namespace MobileGL::MG_Impl::GLImpl {
GLboolean UnmapBuffer(GLenum target); GLboolean UnmapBuffer(GLenum target);
void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); void* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
void* MapBuffer(GLenum target, GLenum access); void* MapBuffer(GLenum target, GLenum access);
void BufferStorage(GLenum target, GLsizeiptr size, const void* data, GLbitfield flags);
void CreateBuffers(GLsizei n, GLuint* buffers);
void NamedBufferStorage(GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags);
void NamedBufferData(GLuint buffer, GLsizeiptr size, const void* data, GLenum usage);
void NamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data);
void CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size);
void ClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data);
void ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format,
GLenum type, const void* data);
void* MapNamedBuffer(GLuint buffer, GLenum access);
void* MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
GLboolean UnmapNamedBuffer(GLuint buffer);
void FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
void GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint* params);
void GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64* params);
void GetNamedBufferPointerv(GLuint buffer, GLenum pname, void** params);
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size); GLsizeiptr size);
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data); void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
@@ -129,6 +129,24 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride); MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirect(mode, indirect, drawcount, stride);
} }
void MultiDrawElementsIndirectCount_Backend(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount(mode, type, indirect, drawcount,
maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount_Backend(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
#ifdef TRACY_ENABLE
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount,
stride);
}
void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex_Backend(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) { const void* indices, GLint basevertex) {
#ifdef TRACY_ENABLE #ifdef TRACY_ENABLE
@@ -272,6 +290,32 @@ namespace MobileGL::MG_Impl::GLImpl {
MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride); MultiDrawArraysIndirect_Backend(mode, indirect, drawcount, stride);
} }
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
auto multiDrawElementsIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawElementsIndirectCount;
if (!multiDrawElementsIndirectCount) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support indirect-parameter indexed draws."));
return;
}
MultiDrawElementsIndirectCount_Backend(mode, type, indirect, drawcount, maxdrawcount, stride);
}
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride) {
auto multiDrawArraysIndirectCount = MG_Backend::gBackendFunctionsTable.GL.MultiDrawArraysIndirectCount;
if (!multiDrawArraysIndirectCount) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not support indirect-parameter array draws."));
return;
}
MultiDrawArraysIndirectCount_Backend(mode, indirect, drawcount, maxdrawcount, stride);
}
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex) { const void* indices, GLint basevertex) {
if (!ValidateCurrentProgramForExecution(__func__)) return; if (!ValidateCurrentProgramForExecution(__func__)) return;
@@ -17,6 +17,10 @@ namespace MobileGL::MG_Impl::GLImpl {
void MemoryBarrierByRegion(GLbitfield barriers); void MemoryBarrierByRegion(GLbitfield barriers);
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);
void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride); void MultiDrawArraysIndirect(GLenum mode, const void* indirect, GLsizei drawcount, GLsizei stride);
void MultiDrawElementsIndirectCount(GLenum mode, GLenum type, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void MultiDrawArraysIndirectCount(GLenum mode, const void* indirect, GLintptr drawcount,
GLsizei maxdrawcount, GLsizei stride);
void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type,
const void* indices, GLint basevertex); const void* indices, GLint basevertex);
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices); void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices);
@@ -10,6 +10,7 @@
#include "../Buffer/GL_Buffer.h" #include "../Buffer/GL_Buffer.h"
#include "../Getter/GL_Getter.h" #include "../Getter/GL_Getter.h"
#include "../Sampler/GL_Sampler.h" #include "../Sampler/GL_Sampler.h"
#include "../Sync/GL_Sync.h"
#include "../Texture/GL_Texture.h" #include "../Texture/GL_Texture.h"
#include "../Drawing/GL_Drawing.h" #include "../Drawing/GL_Drawing.h"
#include "../Program/GL_Program.h" #include "../Program/GL_Program.h"
@@ -103,8 +104,8 @@ DECLARE_GL_FUNCTION_HEAD(void, DrawArrays, GLenum mode, GLint first, GLsizei cou
DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices) DECLARE_GL_FUNCTION_HEAD(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const void* indices) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElements, mode, count, type, indices)
DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap) DECLARE_GL_FUNCTION_HEAD(void, Enable, GLenum cap) DECLARE_GL_FUNCTION_END_NO_RETURN(void, Enable, cap)
DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index) DECLARE_GL_FUNCTION_HEAD(void, EnableVertexAttribArray, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexAttribArray, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, Finish) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Finish) MOBILEGL_GL_API void glFinish() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); }
DECLARE_GL_FUNCTION_STUB_HEAD(void, Flush) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Flush) MOBILEGL_GL_API void glFlush() { MGLOG_D("Implementing function: %s(...)", __FUNCTION__); }
DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_HEAD(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_HEAD(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferTexture2D, target, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode) DECLARE_GL_FUNCTION_HEAD(void, FrontFace, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FrontFace, mode)
@@ -846,7 +847,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttrib4usv, GLuint index, const GLusho
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveRestartIndex, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PrimitiveRestartIndex, index)
DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName) DECLARE_GL_FUNCTION_HEAD(void, GetActiveUniformName, GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformName) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetActiveUniformName, program, uniformIndex, bufSize, length, uniformName)
DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsBaseVertex, GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawcount, const GLint* basevertex) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsBaseVertex, mode, count, type, indices, drawcount, basevertex)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertex, mode) DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertex, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode)
DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void, TexImage2DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage2DMultisample, target, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void, TexImage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexImage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindFragDataLocationIndexed, GLuint program, GLuint colorNumber, GLuint index, const GLchar* name) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindFragDataLocationIndexed, program, colorNumber, index, name)
@@ -980,7 +981,7 @@ DECLARE_GL_FUNCTION_HEAD(GLint, GetProgramResourceLocationIndex, GLuint program,
DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding) DECLARE_GL_FUNCTION_HEAD(void, ShaderStorageBlockBinding, GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ShaderStorageBlockBinding, program, storageBlockIndex, storageBlockBinding)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureView, GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureView, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexAttribLFormat, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexAttribLFormat, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BufferStorage, target, size, data, flags) DECLARE_GL_FUNCTION_HEAD(void, BufferStorage, GLenum target, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BufferStorage, target, size, data, flags)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexImage, GLuint texture, GLint level, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexImage, texture, level, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearTexSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearTexSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers) DECLARE_GL_FUNCTION_STUB_HEAD(void, BindBuffersBase, GLenum target, GLuint first, GLsizei count, const GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindBuffersBase, target, first, count, buffers)
@@ -996,51 +997,51 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, TransformFeedbackBufferRange, GLuint xfb, GL
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbackiv, GLuint xfb, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbackiv, xfb, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki_v, GLuint xfb, GLenum pname, GLuint index, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki_v, xfb, pname, index, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTransformFeedbacki64_v, GLuint xfb, GLenum pname, GLuint index, GLint64* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTransformFeedbacki64_v, xfb, pname, index, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateBuffers, n, buffers) DECLARE_GL_FUNCTION_HEAD(void, CreateBuffers, GLsizei n, GLuint* buffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateBuffers, n, buffers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorage, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferData, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size) DECLARE_GL_FUNCTION_HEAD(void, CopyNamedBufferSubData, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CopyNamedBufferSubData, readBuffer, writeBuffer, readOffset, writeOffset, size)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferData, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubData, GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBuffer, buffer) DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBuffer, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length) DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRange, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteriv, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameteri64v, GLuint buffer, GLenum pname, GLint64* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteri64v, buffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, *params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer, GLsizei n, const GLenum* bufs) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffers, framebuffer, n, bufs)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) DECLARE_GL_FUNCTION_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target) DECLARE_GL_FUNCTION_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers) DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateTextures, target, n, textures) DECLARE_GL_FUNCTION_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateTextures, target, n, textures)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage2DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage2DMultisample, texture, samples, internalformat, width, height, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureStorage3DMultisample, GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureStorage3DMultisample, texture, samples, internalformat, width, height, depth, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage1D, texture, level, xoffset, width, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels) DECLARE_GL_FUNCTION_HEAD(void, TextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureSubImage3D, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage1D, texture, level, xoffset, width, format, imageSize, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CompressedTextureSubImage2D, texture, level, xoffset, yoffset, width, height, format, imageSize, data)
@@ -1048,31 +1049,31 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, CompressedTextureSubImage3D, GLuint texture,
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage1D, GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage1D, texture, level, xoffset, x, y, width)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage2D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage2D, texture, level, xoffset, yoffset, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, CopyTextureSubImage3D, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CopyTextureSubImage3D, texture, level, xoffset, yoffset, zoffset, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterf, texture, pname, param) DECLARE_GL_FUNCTION_HEAD(void, TextureParameterf, GLuint texture, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameterf, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterfv, GLuint texture, GLenum pname, const GLfloat* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterfv, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteri, texture, pname, param) DECLARE_GL_FUNCTION_HEAD(void, TextureParameteri, GLuint texture, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteri, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIiv, GLuint texture, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameterIuiv, GLuint texture, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameterIuiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureParameteriv, texture, pname, param) DECLARE_GL_FUNCTION_HEAD(void, TextureParameteriv, GLuint texture, GLenum pname, const GLint* param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureParameteriv, texture, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmap, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmap, texture)
DECLARE_GL_FUNCTION_STUB_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, BindTextureUnit, unit, texture) DECLARE_GL_FUNCTION_HEAD(void, BindTextureUnit, GLuint unit, GLuint texture) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BindTextureUnit, unit, texture)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_HEAD(void, GetTextureImage, GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureImage, texture, level, format, type, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureImage, GLuint texture, GLint level, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureImage, texture, level, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameterfv, GLuint texture, GLint level, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameterfv, texture, level, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetTextureLevelParameteriv, GLuint texture, GLint level, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureLevelParameteriv, texture, level, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterfv, GLuint texture, GLenum pname, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterfv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIiv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameterIuiv, GLuint texture, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameterIuiv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetTextureParameteriv, GLuint texture, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureParameteriv, texture, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CreateVertexArrays, n, arrays) DECLARE_GL_FUNCTION_HEAD(void, CreateVertexArrays, GLsizei n, GLuint* arrays) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateVertexArrays, n, arrays)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index) DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttrib, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer) DECLARE_GL_FUNCTION_HEAD(void, VertexArrayElementBuffer, GLuint vaobj, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayElementBuffer, vaobj, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride) DECLARE_GL_FUNCTION_HEAD(void, VertexArrayVertexBuffer, GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayVertexBuffer, vaobj, bindingindex, buffer, offset, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexBuffers, GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr* offsets, const GLsizei* strides) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexBuffers, vaobj, first, count, buffers, offsets, strides)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribBinding, GLuint vaobj, GLuint attribindex, GLuint bindingindex) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribBinding, vaobj, attribindex, bindingindex)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset) DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribFormat, vaobj, attribindex, size, type, normalized, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_HEAD(void, VertexArrayAttribIFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_END_NO_RETURN(void, VertexArrayAttribIFormat, vaobj, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayAttribLFormat, GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayAttribLFormat, vaobj, attribindex, size, type, relativeoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayBindingDivisor, GLuint vaobj, GLuint bindingindex, GLuint divisor) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayBindingDivisor, vaobj, bindingindex, divisor)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayiv, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayiv, vaobj, pname, param)
@@ -1085,7 +1086,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjecti64v, GLuint id, GLuint
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectiv, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectui64v, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectui64v, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetQueryBufferObjectuiv, GLuint id, GLuint buffer, GLenum pname, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetQueryBufferObjectuiv, id, buffer, pname, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_HEAD(void, GetTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetCompressedTextureSubImage, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetCompressedTextureSubImage, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnCompressedTexImage, GLenum target, GLint lod, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnCompressedTexImage, target, lod, bufSize, pixels)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnTexImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnTexImage, target, level, format, type, bufSize, pixels)
@@ -1104,8 +1105,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnHistogram, GLenum target, GLboolean rese
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnMinmax, GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void* values) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnMinmax, target, reset, format, type, bufSize, values)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, ) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBarrier, void) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBarrier, )
DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) DECLARE_GL_FUNCTION_STUB_HEAD(void, SpecializeShader, GLuint shader, const GLchar* pEntryPoint, GLuint numSpecializationConstants, const GLuint* pConstantIndex, const GLuint* pConstantValue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SpecializeShader, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCount, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCount, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp) DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClamp, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClamp, factor, units, clamp)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW) DECLARE_GL_FUNCTION_STUB_HEAD(void, PrimitiveBoundingBoxARB, GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) DECLARE_GL_FUNCTION_STUB_END(void, PrimitiveBoundingBoxARB, minX, minY, minZ, minW, maxX, maxY, maxZ, maxW)
DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture) DECLARE_GL_FUNCTION_STUB_HEAD(GLuint64, GetTextureHandleARB, GLuint texture) DECLARE_GL_FUNCTION_STUB_END(GLuint64, GetTextureHandleARB, texture)
@@ -1214,8 +1215,8 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, Histogram, GLenum target, GLsizei width, GLe
DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink) DECLARE_GL_FUNCTION_STUB_HEAD(void, Minmax, GLenum target, GLenum internalformat, GLboolean sink) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, Minmax, target, internalformat, sink)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetHistogram, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetHistogram, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, ResetMinmax, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ResetMinmax, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawArraysIndirectCountARB, mode, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawArraysIndirectCountARB, GLenum mode, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawArraysIndirectCount, mode, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiDrawElementsIndirectCountARB, mode, type, indirect, drawcount, maxdrawcount, stride) DECLARE_GL_FUNCTION_HEAD(void, MultiDrawElementsIndirectCountARB, GLenum mode, GLenum type, const void* indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride) DECLARE_GL_FUNCTION_END_NO_RETURN(void, MultiDrawElementsIndirectCount, mode, type, indirect, drawcount, maxdrawcount, stride)
DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index) DECLARE_GL_FUNCTION_STUB_HEAD(void, CurrentPaletteMatrixARB, GLint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, CurrentPaletteMatrixARB, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexubvARB, GLint size, const GLubyte* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexubvARB, size, indices)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixIndexusvARB, GLint size, const GLushort* indices) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixIndexusvARB, size, indices)
@@ -1845,11 +1846,11 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposefEXT, GLenum mode, const
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixLoadTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixLoadTransposedEXT, mode, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposefEXT, GLenum mode, const GLfloat* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposefEXT, mode, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m) DECLARE_GL_FUNCTION_STUB_HEAD(void, MatrixMultTransposedEXT, GLenum mode, const GLdouble* m) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MatrixMultTransposedEXT, mode, m)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferDataEXT, buffer, size, data, usage) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferDataEXT, GLuint buffer, GLsizeiptr size, const void* data, GLenum usage) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferData, buffer, size, data, usage)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferSubDataEXT, buffer, offset, size, data) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_STUB_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END(GLboolean, UnmapNamedBufferEXT, buffer) DECLARE_GL_FUNCTION_HEAD(GLboolean, UnmapNamedBufferEXT, GLuint buffer) DECLARE_GL_FUNCTION_END(GLboolean, UnmapNamedBuffer, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferParameterivEXT, buffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferParameterivEXT, GLuint buffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferParameteriv, buffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferPointervEXT, buffer, pname, *params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointervEXT, GLuint buffer, GLenum pname, void** params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferPointerv, buffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedBufferSubDataEXT, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedBufferSubDataEXT, buffer, offset, size, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferEXT, GLuint texture, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferEXT, texture, target, internalformat, buffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer) DECLARE_GL_FUNCTION_STUB_HEAD(void, MultiTexBufferEXT, GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MultiTexBufferEXT, texunit, target, internalformat, buffer)
@@ -1884,15 +1885,15 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterdvEXT, GLuint p
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramLocalParameterfvEXT, GLuint program, GLenum target, GLuint index, GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramLocalParameterfvEXT, program, target, index, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramivEXT, GLuint program, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramivEXT, program, target, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedProgramStringEXT, GLuint program, GLenum target, GLenum pname, void* string) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedProgramStringEXT, program, target, pname, string)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageEXT, renderbuffer, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedRenderbufferParameterivEXT, renderbuffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameterivEXT, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleEXT, renderbuffer, samples, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedRenderbufferStorageMultisampleCoverageEXT, GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedRenderbufferStorageMultisampleCoverageEXT, renderbuffer, coverageSamples, colorSamples, internalformat, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target) DECLARE_GL_FUNCTION_STUB_HEAD(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_STUB_END(GLenum, CheckNamedFramebufferStatusEXT, framebuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture1DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture1DEXT, framebuffer, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture2DEXT, framebuffer, attachment, textarget, texture, level)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferTexture3DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferTexture3DEXT, framebuffer, attachment, textarget, texture, level, zoffset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferRenderbufferEXT, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferAttachmentParameterivEXT, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameterivEXT, framebuffer, attachment, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateTextureMipmapEXT, GLuint texture, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateTextureMipmapEXT, texture, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target) DECLARE_GL_FUNCTION_STUB_HEAD(void, GenerateMultiTexMipmapEXT, GLenum texunit, GLenum target) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GenerateMultiTexMipmapEXT, texunit, target)
@@ -1918,16 +1919,16 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribOffsetEXT, GLuint vao
DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset) DECLARE_GL_FUNCTION_STUB_HEAD(void, VertexArrayVertexAttribIOffsetEXT, GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, VertexArrayVertexAttribIOffsetEXT, vaobj, buffer, index, size, type, stride, offset)
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array) DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayEXT, vaobj, array)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array) DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayEXT, GLuint vaobj, GLenum array) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayEXT, vaobj, array)
DECLARE_GL_FUNCTION_STUB_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, EnableVertexArrayAttribEXT, vaobj, index) DECLARE_GL_FUNCTION_HEAD(void, EnableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, EnableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, DisableVertexArrayAttribEXT, vaobj, index) DECLARE_GL_FUNCTION_HEAD(void, DisableVertexArrayAttribEXT, GLuint vaobj, GLuint index) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DisableVertexArrayAttrib, vaobj, index)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegervEXT, GLuint vaobj, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegervEXT, vaobj, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointervEXT, GLuint vaobj, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointervEXT, vaobj, pname, *param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayIntegeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayIntegeri_vEXT, vaobj, index, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetVertexArrayPointeri_vEXT, GLuint vaobj, GLuint index, GLenum pname, void** param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetVertexArrayPointeri_vEXT, vaobj, index, pname, *param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FlushMappedNamedBufferRangeEXT, buffer, offset, length) DECLARE_GL_FUNCTION_HEAD(void, FlushMappedNamedBufferRangeEXT, GLuint buffer, GLintptr offset, GLsizeiptr length) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FlushMappedNamedBufferRange, buffer, offset, length)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedBufferStorageEXT, buffer, size, data, flags) DECLARE_GL_FUNCTION_HEAD(void, NamedBufferStorageEXT, GLuint buffer, GLsizeiptr size, const void* data, GLbitfield flags) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedBufferStorage, buffer, size, data, flags)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferDataEXT, buffer, internalformat, format, type, data) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferDataEXT, GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferData, buffer, internalformat, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedBufferSubDataEXT, buffer, internalformat, offset, size, format, type, data) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedBufferSubDataEXT, GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedBufferSubData, buffer, internalformat, offset, size, format, type, data)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteriEXT, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteriEXT, framebuffer, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameterivEXT, GLuint framebuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameterivEXT, framebuffer, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x) DECLARE_GL_FUNCTION_STUB_HEAD(void, ProgramUniform1dEXT, GLuint program, GLint location, GLdouble x) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProgramUniform1dEXT, program, location, x)
@@ -2045,7 +2046,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetPixelTransformParameterfvEXT, GLenum targ
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfEXT, GLenum pname, GLfloat param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfEXT, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, PointParameterfvEXT, GLenum pname, const GLfloat* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PointParameterfvEXT, pname, params)
DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp) DECLARE_GL_FUNCTION_STUB_HEAD(void, PolygonOffsetClampEXT, GLfloat factor, GLfloat units, GLfloat clamp) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PolygonOffsetClampEXT, factor, units, clamp)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ProvokingVertexEXT, mode) DECLARE_GL_FUNCTION_HEAD(void, ProvokingVertexEXT, GLenum mode) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ProvokingVertex, mode)
DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_HEAD(void, RasterSamplesEXT, GLuint samples, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, RasterSamplesEXT, samples, fixedsamplelocations)
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue) DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bEXT, GLbyte red, GLbyte green, GLbyte blue) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bEXT, red, green, blue)
DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v) DECLARE_GL_FUNCTION_STUB_HEAD(void, SecondaryColor3bvEXT, const GLbyte* v) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, SecondaryColor3bvEXT, v)
@@ -2964,8 +2965,8 @@ MOBILEGL_GL_API void glGetObjectLabelEXT(GLenum identifier, GLuint name, GLsizei
} }
MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) { MOBILEGL_GL_API void* glMapNamedBuffer(GLuint buffer, GLenum access) {
MGLOG_W("Stub function: %s(...)", __FUNCTION__); MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
return nullptr; return MobileGL::MG_Impl::GLImpl::MapNamedBuffer(buffer, access);
} }
MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) { MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
@@ -2973,8 +2974,8 @@ MOBILEGL_GL_API void* glMapNamedBufferEXT(GLuint buffer, GLenum access) {
} }
MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { MOBILEGL_GL_API void* glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
MGLOG_W("Stub function: %s(...)", __FUNCTION__); MGLOG_D("Implementing function: %s(...)", __FUNCTION__);
return nullptr; return MobileGL::MG_Impl::GLImpl::MapNamedBufferRange(buffer, offset, length, access);
} }
MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) { MOBILEGL_GL_API void* glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access) {
@@ -159,6 +159,39 @@ namespace MobileGL::MG_Impl::GLImpl {
mask, filter); mask, filter);
} }
void BlitNamedFramebuffer_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
auto blitNamedFramebuffer = MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer;
if (!blitNamedFramebuffer) {
MGLOG_E("glBlitNamedFramebuffer skipped: backend does not implement explicit framebuffer blit.");
return;
}
blitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
dstY1, mask, filter);
}
void ClearNamedFramebufferfv_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value) {
auto clearNamedFramebufferfv = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv;
if (!clearNamedFramebufferfv) {
MGLOG_E("glClearNamedFramebufferfv skipped: backend does not implement explicit framebuffer clear.");
return;
}
clearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
auto clearNamedFramebufferfi = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi;
if (!clearNamedFramebufferfi) {
MGLOG_E("glClearNamedFramebufferfi skipped: backend does not implement explicit framebuffer clear.");
return;
}
clearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
}
void SampleMaski_State(GLuint maskNumber, GLbitfield mask) { void SampleMaski_State(GLuint maskNumber, GLbitfield mask) {
if (maskNumber != 0) { if (maskNumber != 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -209,23 +242,19 @@ namespace MobileGL::MG_Impl::GLImpl {
renderbufferObject->SetSamples(samples); renderbufferObject->SetSamples(samples);
} }
void RenderbufferStorage_State(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { void AllocateRenderbufferStorage_State(const SharedPtr<MG_State::GLState::RenderbufferObject>& renderbufferObject,
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target); GLenum internalformat, GLsizei width, GLsizei height, const char* caller) {
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
auto& renderbufferObject = bindingSlot.GetBoundObject();
if (!renderbufferObject) { if (!renderbufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "No renderbuffer object is available."));
"Renderbuffer target is bound to no renderbuffer object."));
return; return;
} }
TextureInternalFormat format = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat); TextureInternalFormat format = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
if (!TextureImpl::ValidateTextureInternalFormat(format)) return; if (!TextureImpl::ValidateTextureInternalFormat(format)) return;
if (width < 0 || height < 0) { if (width < 0 || height < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "RenderbufferStorage_State", ErrorCode::InvalidValue, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
"Width and height must be non-negative.")); "Width and height must be non-negative."));
return; return;
} }
@@ -234,6 +263,14 @@ namespace MobileGL::MG_Impl::GLImpl {
renderbufferObject->SetSamples(0); renderbufferObject->SetSamples(0);
} }
void RenderbufferStorage_State(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(rbTarget);
auto& renderbufferObject = bindingSlot.GetBoundObject();
AllocateRenderbufferStorage_State(renderbufferObject, internalformat, width, height, "RenderbufferStorage_State");
}
GLboolean IsRenderbuffer_State(GLuint renderbuffer) { GLboolean IsRenderbuffer_State(GLuint renderbuffer) {
return MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer); return MG_State::pGLContext->ValidateRenderbufferObject(renderbuffer);
} }
@@ -352,11 +389,55 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenRenderbuffers_State", "n must be non-negative"));
return; return;
} }
static thread_local Vector<GLuint> renderbufferNames; Vector<GLuint> renderbufferNames;
MG_State::pGLContext->GenRenderbufferNames(n, renderbufferNames); MG_State::pGLContext->GenRenderbufferNames(n, renderbufferNames);
Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n)); Memcpy(renderbuffers, renderbufferNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
} }
void CreateRenderbuffers_State(GLsizei n, GLuint* renderbuffers) {
if (n < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateRenderbuffers_State", "n must be non-negative"));
return;
}
if (n > 0 && !renderbuffers) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateRenderbuffers_State",
"Renderbuffer output pointer cannot be null."));
return;
}
Vector<GLuint> renderbufferNames;
MG_State::pGLContext->GenRenderbufferNames(static_cast<Uint>(n), renderbufferNames);
for (GLsizei i = 0; i < n; ++i) {
renderbuffers[i] = renderbufferNames[i];
MG_State::pGLContext->CreateRenderbufferObject(renderbufferNames[i]);
}
}
SharedPtr<MG_State::GLState::RenderbufferObject> GetNamedRenderbufferObject_State(GLuint renderbuffer,
const char* caller) {
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, false)) return nullptr;
auto& renderbufferObject = MG_State::pGLContext->GetRenderbufferObject(renderbuffer);
if (!renderbufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
std::format("Renderbuffer object {} does not exist.", renderbuffer)));
return nullptr;
}
return renderbufferObject;
}
void NamedRenderbufferStorage_State(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) {
auto renderbufferObject = GetNamedRenderbufferObject_State(renderbuffer, "NamedRenderbufferStorage_State");
AllocateRenderbufferStorage_State(renderbufferObject, internalformat, width, height,
"NamedRenderbufferStorage_State");
}
void GenFramebuffers_State(GLsizei n, GLuint* framebuffers) { void GenFramebuffers_State(GLsizei n, GLuint* framebuffers) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -364,11 +445,49 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GenFramebuffers_State", "n must be non-negative"));
return; return;
} }
static thread_local Vector<GLuint> framebuffersNames; Vector<GLuint> framebuffersNames;
MG_State::pGLContext->GenFramebufferNames(n, framebuffersNames); MG_State::pGLContext->GenFramebufferNames(n, framebuffersNames);
Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n)); Memcpy(framebuffers, framebuffersNames.data(), sizeof(GLuint) * static_cast<SizeT>(n));
} }
void CreateFramebuffers_State(GLsizei n, GLuint* framebuffers) {
if (n < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateFramebuffers_State", "n must be non-negative"));
return;
}
if (n > 0 && !framebuffers) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateFramebuffers_State",
"Framebuffer output pointer cannot be null."));
return;
}
Vector<GLuint> framebufferNames;
MG_State::pGLContext->GenFramebufferNames(static_cast<Uint>(n), framebufferNames);
for (GLsizei i = 0; i < n; ++i) {
framebuffers[i] = framebufferNames[i];
MG_State::pGLContext->CreateFramebufferObject(framebufferNames[i]);
}
}
SharedPtr<MG_State::GLState::FramebufferObject> GetNamedFramebufferObject_State(GLuint framebuffer,
const char* caller) {
if (!FramebufferImpl::ValidateFramebufferName(framebuffer, false)) return nullptr;
auto& framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
if (!framebufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
std::format("Framebuffer object {} does not exist.", framebuffer)));
return nullptr;
}
return framebufferObject;
}
void FramebufferTextureLayer_State(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { void FramebufferTextureLayer_State(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
if (texture == 0) { if (texture == 0) {
const TextureUploadTarget detachTarget = TextureUploadTarget::Texture2D; const TextureUploadTarget detachTarget = TextureUploadTarget::Texture2D;
@@ -497,6 +616,46 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget); AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
AttachFramebufferTextureWithUploadTarget(__func__, target, attachment, texture, level, textureUploadTarget);
}
void NamedFramebufferTexture_State(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
NamedFramebufferTexture_State(framebuffer, GL_DEPTH_ATTACHMENT, texture, level);
NamedFramebufferTexture_State(framebuffer, GL_STENCIL_ATTACHMENT, texture, level);
return;
}
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferTexture_State");
if (!framebufferObject) return;
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
if (!TextureImpl::ValidateTextureName(texture, true)) return;
if (texture == 0) {
framebufferObject->Detach(attachmentType);
return;
}
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
if (!textureObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "NamedFramebufferTexture_State",
std::format("Texture object {} is not valid.", texture)));
return;
}
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
if (!ResolveRepresentableFramebufferTextureUploadTarget(*textureObject, textureUploadTarget)) {
RecordUnsupportedFramebufferTextureAttachmentError(
"NamedFramebufferTexture_State",
"Layered or multi-image framebuffer texture targets are not fully represented by the current framebuffer attachment model.");
return;
}
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level);
} }
void FramebufferRenderbuffer_State(GLenum target, GLenum attachment, GLenum renderbuffertarget, void FramebufferRenderbuffer_State(GLenum target, GLenum attachment, GLenum renderbuffertarget,
@@ -539,7 +698,37 @@ namespace MobileGL::MG_Impl::GLImpl {
framebufferObject->AttachRenderbuffer(attachmentType, renderbufferObject); framebufferObject->AttachRenderbuffer(attachmentType, renderbufferObject);
} }
void DrawBuffers_State(GLsizei n, const GLenum* bufs) { void NamedFramebufferRenderbuffer_State(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer) {
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
NamedFramebufferRenderbuffer_State(framebuffer, GL_DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer);
NamedFramebufferRenderbuffer_State(framebuffer, GL_STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer);
return;
}
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferRenderbuffer_State");
if (!framebufferObject) return;
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
RenderbufferTarget rbTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(renderbuffertarget);
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
if (!FramebufferImpl::ValidateRenderbufferTarget(rbTarget)) return;
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer)) return;
if (renderbuffer == 0) {
framebufferObject->Detach(attachmentType);
return;
}
auto renderbufferObject =
GetNamedRenderbufferObject_State(renderbuffer, "NamedFramebufferRenderbuffer_State");
if (!renderbufferObject) return;
framebufferObject->AttachRenderbuffer(attachmentType, renderbufferObject);
}
void DrawBuffersForFramebuffer_State(const SharedPtr<MG_State::GLState::FramebufferObject>& fbo, Bool isDefaultFBO,
GLsizei n, const GLenum* bufs) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue, ErrorCode::InvalidValue,
@@ -551,17 +740,12 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`n` is greater than `GL_MAX_DRAW_BUFFERS`."));
return; return;
} }
// Get bound framebuffer
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
auto& fbo = bindingSlot.GetBoundObject();
if (!fbo) { if (!fbo) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No framebuffer bound to draw target.")); MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Framebuffer object is null."));
return; return;
} }
bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1}; static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
std::fill(existenceMap, existenceMap + (SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount, -1); std::fill(existenceMap, existenceMap + (SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount, -1);
@@ -634,6 +818,13 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
} }
void DrawBuffers_State(GLsizei n, const GLenum* bufs) {
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw);
auto& fbo = bindingSlot.GetBoundObject();
const bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
DrawBuffersForFramebuffer_State(fbo, isDefaultFBO, n, bufs);
}
void DrawBuffer_State(GLenum buf) { void DrawBuffer_State(GLenum buf) {
if (buf == GL_NONE) { if (buf == GL_NONE) {
DrawBuffers_State(0, nullptr); DrawBuffers_State(0, nullptr);
@@ -699,6 +890,114 @@ namespace MobileGL::MG_Impl::GLImpl {
fbo->SetReadBuffer(attType); fbo->SetReadBuffer(attType);
} }
void NamedFramebufferDrawBuffers_State(GLuint framebuffer, GLsizei n, const GLenum* bufs) {
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferDrawBuffers_State");
if (!framebufferObject) return;
DrawBuffersForFramebuffer_State(framebufferObject, false, n, bufs);
}
void NamedFramebufferDrawBuffer_State(GLuint framebuffer, GLenum buf) {
if (buf == GL_NONE) {
NamedFramebufferDrawBuffers_State(framebuffer, 0, nullptr);
} else {
GLenum bufs[] = {buf};
NamedFramebufferDrawBuffers_State(framebuffer, 1, bufs);
}
}
void NamedFramebufferReadBuffer_State(GLuint framebuffer, GLenum src) {
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferReadBuffer_State");
if (!framebufferObject) return;
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(src);
if (attType == FramebufferAttachmentType::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "NamedFramebufferReadBuffer_State",
std::format("`src` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(src))));
return;
}
framebufferObject->SetReadBuffer(attType);
}
SharedPtr<MG_State::GLState::FramebufferObject> GetFramebufferObjectForNamedClear(GLuint framebuffer,
const char* caller) {
return framebuffer == 0 ? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
: GetNamedFramebufferObject_State(framebuffer, caller);
}
Bool ValidateNamedClearfv_State(GLenum buffer, GLint drawbuffer, const GLfloat* value, const char* caller) {
if (!value) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "value pointer cannot be null."));
return false;
}
switch (buffer) {
case GL_COLOR:
if (drawbuffer < 0 ||
drawbuffer >= static_cast<GLint>(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "color drawbuffer index is out of range."));
return false;
}
return true;
case GL_DEPTH:
if (drawbuffer != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "depth clear requires drawbuffer 0."));
return false;
}
return true;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("buffer {} is not accepted for glClearNamedFramebufferfv.",
MG_Util::ConvertGLEnumToString(buffer))));
return false;
}
}
Bool ValidateNamedClearfi_State(GLenum buffer, GLint drawbuffer, const char* caller) {
if (buffer != GL_DEPTH_STENCIL) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("buffer {} is not accepted for glClearNamedFramebufferfi.",
MG_Util::ConvertGLEnumToString(buffer))));
return false;
}
if (drawbuffer != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "depth/stencil clear requires drawbuffer 0."));
return false;
}
return true;
}
void ClearNamedFramebufferfv_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) {
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferfv_State");
if (!framebufferObject) return;
if (!ValidateNamedClearfv_State(buffer, drawbuffer, value, "ClearNamedFramebufferfv_State")) return;
ClearNamedFramebufferfv_Backend(framebufferObject, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth,
GLint stencil) {
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferfi_State");
if (!framebufferObject) return;
if (!ValidateNamedClearfi_State(buffer, drawbuffer, "ClearNamedFramebufferfi_State")) return;
ClearNamedFramebufferfi_Backend(framebufferObject, buffer, drawbuffer, depth, stencil);
}
void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -773,6 +1072,122 @@ namespace MobileGL::MG_Impl::GLImpl {
return GL_FRAMEBUFFER_COMPLETE; return GL_FRAMEBUFFER_COMPLETE;
} }
GLenum CheckNamedFramebufferStatus_State(GLuint framebuffer, GLenum target) {
if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CheckNamedFramebufferStatus_State",
std::format("target {} is not accepted.",
MG_Util::ConvertGLEnumToString(target))));
return GL_FRAMEBUFFER_UNDEFINED;
}
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "CheckNamedFramebufferStatus_State");
if (!framebufferObject) return GL_FRAMEBUFFER_UNDEFINED;
if (!framebufferObject->CheckCompleteness()) {
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
}
if (IsActiveBackendDirectVulkan() &&
IsUnsupportedFramebufferForDirectVulkan(*framebufferObject)) {
return GL_FRAMEBUFFER_UNSUPPORTED;
}
return GL_FRAMEBUFFER_COMPLETE;
}
void GetFramebufferAttachmentParameteriv_Object(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject, GLenum attachment, GLenum pname,
GLint* params, const char* caller) {
if (params == nullptr) return;
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
FramebufferAttachmentType attachmentType = depthStencilAlias
? FramebufferAttachmentType::Depth
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
if (!depthStencilAlias) {
return &framebufferObject->GetAttachment(attachmentType);
}
const auto& depthAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Depth);
if (depthAttachment.IsValid() && !depthAttachment.IsEmpty()) return &depthAttachment;
const auto& stencilAttachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Stencil);
if (stencilAttachment.IsValid() && !stencilAttachment.IsEmpty()) return &stencilAttachment;
return nullptr;
}();
switch (pname) {
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
*params = GL_NONE;
} else if (attachmentObject->IsTexture()) {
*params = GL_TEXTURE;
} else if (attachmentObject->IsRenderbuffer()) {
*params = GL_RENDERBUFFER;
} else {
*params = GL_NONE;
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
*params = 0;
} else if (attachmentObject->IsTexture()) {
const auto& textureObject = attachmentObject->GetTexture();
*params = textureObject ? static_cast<GLint>(textureObject->GetExternalIndex()) : 0;
} else if (attachmentObject->IsRenderbuffer()) {
const auto& renderbufferObject = attachmentObject->GetRenderbuffer();
*params = renderbufferObject ? static_cast<GLint>(renderbufferObject->GetExternalIndex()) : 0;
} else {
*params = 0;
}
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
*params = (attachmentObject != nullptr && attachmentObject->IsTexture() && attachmentObject->IsValid())
? static_cast<GLint>(attachmentObject->GetTextureLevel())
: 0;
break;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
*params = 0;
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
return;
}
}
void GetNamedFramebufferAttachmentParameteriv_State(GLuint framebuffer, GLenum attachment, GLenum pname,
GLint* params) {
auto framebufferObject =
GetNamedFramebufferObject_State(framebuffer, "GetNamedFramebufferAttachmentParameteriv_State");
if (!framebufferObject) return;
GetFramebufferAttachmentParameteriv_Object(framebufferObject, attachment, pname, params,
"GetNamedFramebufferAttachmentParameteriv_State");
}
void BlitNamedFramebuffer_State(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0,
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) {
auto readObject = readFramebuffer == 0
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
: GetNamedFramebufferObject_State(readFramebuffer, "BlitNamedFramebuffer_State");
auto drawObject = drawFramebuffer == 0
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
: GetNamedFramebufferObject_State(drawFramebuffer, "BlitNamedFramebuffer_State");
if (!readObject || !drawObject) return;
BlitNamedFramebuffer_Backend(readObject, drawObject, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
void BindRenderbuffer_State(GLenum target, GLuint renderbuffer) { void BindRenderbuffer_State(GLenum target, GLuint renderbuffer) {
if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, true)) return; if (!FramebufferImpl::ValidateRenderbufferName(renderbuffer, true)) return;
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target); RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
@@ -814,18 +1229,15 @@ namespace MobileGL::MG_Impl::GLImpl {
bindingSlot.Bind(framebufferObject); bindingSlot.Bind(framebufferObject);
} }
void GetRenderbufferParameteriv_State(GLenum target, GLenum pname, GLint* params) { void GetRenderbufferParameterivForObject_State(const SharedPtr<MG_State::GLState::RenderbufferObject>&
renderbufferObject,
GLenum pname, GLint* params, const char* caller) {
if (!params) return; if (!params) return;
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
auto& renderbufferObject = bindingSlot.GetBoundObject();
if (!renderbufferObject) { if (!renderbufferObject) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetRenderbufferParameteriv_State", MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "No renderbuffer object is available."));
"Renderbuffer target is bound to no renderbuffer object."));
return; return;
} }
@@ -864,12 +1276,27 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum, ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>( MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", "GetRenderbufferParameteriv_State", "MG_Impl/GLImpl", caller,
std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname)))); std::format("pname {} is not an accepted value.", MG_Util::ConvertGLEnumToString(pname))));
return; return;
} }
} }
void GetRenderbufferParameteriv_State(GLenum target, GLenum pname, GLint* params) {
RenderbufferTarget renderbufferTarget = MG_Util::ConvertGLEnumToRenderbufferTarget(target);
if (!FramebufferImpl::ValidateRenderbufferTarget(renderbufferTarget)) return;
auto& bindingSlot = MG_State::pGLContext->GetRenderbufferBindingSlot(renderbufferTarget);
auto& renderbufferObject = bindingSlot.GetBoundObject();
GetRenderbufferParameterivForObject_State(renderbufferObject, pname, params, "GetRenderbufferParameteriv_State");
}
void GetNamedRenderbufferParameteriv_State(GLuint renderbuffer, GLenum pname, GLint* params) {
auto renderbufferObject =
GetNamedRenderbufferObject_State(renderbuffer, "GetNamedRenderbufferParameteriv_State");
GetRenderbufferParameterivForObject_State(renderbufferObject, pname, params,
"GetNamedRenderbufferParameteriv_State");
}
void ClearBufferfi_Backend(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { void ClearBufferfi_Backend(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
MG_Backend::gBackendFunctionsTable.GL.ClearBufferfi(buffer, drawbuffer, depth, stencil); MG_Backend::gBackendFunctionsTable.GL.ClearBufferfi(buffer, drawbuffer, depth, stencil);
} }
@@ -975,8 +1402,9 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject(); MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) { if (pixelPackBufferObject) {
// Check if PBO is mapped // Persistent mappings remain legal GPU transfer destinations.
if (pixelPackBufferObject->IsMapped()) { if (pixelPackBufferObject->IsMapped() &&
!(pixelPackBufferObject->GetMappingAccess() & BufferMappingAccessBit::Persistent)) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State", ErrorCode::InvalidOperation, MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ReadPixels_State",
"Pixel pack buffer is currently mapped")); "Pixel pack buffer is currently mapped"));
@@ -1064,10 +1492,26 @@ namespace MobileGL::MG_Impl::GLImpl {
GenRenderbuffers_State(n, renderbuffers); GenRenderbuffers_State(n, renderbuffers);
} }
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers) {
CreateRenderbuffers_State(n, renderbuffers);
}
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) {
NamedRenderbufferStorage_State(renderbuffer, internalformat, width, height);
}
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params) {
GetNamedRenderbufferParameteriv_State(renderbuffer, pname, params);
}
void GenFramebuffers(GLsizei n, GLuint* framebuffers) { void GenFramebuffers(GLsizei n, GLuint* framebuffers) {
GenFramebuffers_State(n, framebuffers); GenFramebuffers_State(n, framebuffers);
} }
void CreateFramebuffers(GLsizei n, GLuint* framebuffers) {
CreateFramebuffers_State(n, framebuffers);
}
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
FramebufferTextureLayer_State(target, attachment, texture, level, layer); FramebufferTextureLayer_State(target, attachment, texture, level, layer);
} }
@@ -1089,10 +1533,39 @@ namespace MobileGL::MG_Impl::GLImpl {
FramebufferTexture_State(target, attachment, texture, level); FramebufferTexture_State(target, attachment, texture, level);
} }
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) {
NamedFramebufferTexture_State(framebuffer, attachment, texture, level);
}
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf) {
NamedFramebufferDrawBuffer_State(framebuffer, buf);
}
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs) {
NamedFramebufferDrawBuffers_State(framebuffer, n, bufs);
}
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src) {
NamedFramebufferReadBuffer_State(framebuffer, src);
}
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) {
ClearNamedFramebufferfv_State(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
ClearNamedFramebufferfi_State(framebuffer, buffer, drawbuffer, depth, stencil);
}
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
FramebufferRenderbuffer_State(target, attachment, renderbuffertarget, renderbuffer); FramebufferRenderbuffer_State(target, attachment, renderbuffertarget, renderbuffer);
} }
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer) {
NamedFramebufferRenderbuffer_State(framebuffer, attachment, renderbuffertarget, renderbuffer);
}
void DrawBuffer(GLenum buf) { void DrawBuffer(GLenum buf) {
DrawBuffer_State(buf); DrawBuffer_State(buf);
} }
@@ -1117,6 +1590,21 @@ namespace MobileGL::MG_Impl::GLImpl {
return CheckFramebufferStatus_State(target); return CheckFramebufferStatus_State(target);
} }
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) {
return CheckNamedFramebufferStatus_State(framebuffer, target);
}
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) {
GetNamedFramebufferAttachmentParameteriv_State(framebuffer, attachment, pname, params);
}
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
GLenum filter) {
BlitNamedFramebuffer_State(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1,
dstY1, mask, filter);
}
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) {
BlitFramebuffer_Backend(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); BlitFramebuffer_Backend(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
@@ -24,19 +24,36 @@ namespace MobileGL::MG_Impl::GLImpl {
GLboolean IsRenderbuffer(GLuint renderbuffer); GLboolean IsRenderbuffer(GLuint renderbuffer);
void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
void GenRenderbuffers(GLsizei n, GLuint* renderbuffers); void GenRenderbuffers(GLsizei n, GLuint* renderbuffers);
void CreateRenderbuffers(GLsizei n, GLuint* renderbuffers);
void NamedRenderbufferStorage(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
void GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, GLint* params);
void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget,
GLuint renderbuffer);
void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers);
void BindRenderbuffer(GLenum target, GLuint renderbuffer); void BindRenderbuffer(GLenum target, GLuint renderbuffer);
void SampleMaski(GLuint maskNumber, GLbitfield mask); void SampleMaski(GLuint maskNumber, GLbitfield mask);
GLboolean IsFramebuffer(GLuint framebuffer); GLboolean IsFramebuffer(GLuint framebuffer);
void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
void GenFramebuffers(GLsizei n, GLuint* framebuffers); void GenFramebuffers(GLsizei n, GLuint* framebuffers);
void CreateFramebuffers(GLsizei n, GLuint* framebuffers);
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, void FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level,
GLint zoffset); GLint zoffset);
void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); void FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level); void FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
void NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
void NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf);
void NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, const GLenum* bufs);
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src);
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
GLenum filter);
void DrawBuffer(GLenum buf); void DrawBuffer(GLenum buf);
void DrawBuffers(GLsizei n, const GLenum* bufs); void DrawBuffers(GLsizei n, const GLenum* bufs);
void ReadBuffer(GLenum src); void ReadBuffer(GLenum src);
+42 -1
View File
@@ -664,6 +664,28 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
switch (pname) {
case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
if (MG_Backend::pActiveBackendObject) {
params[0] = static_cast<GLint64>(
MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBlockSize);
} else {
params[0] = static_cast<GLint64>(MG_Backend::DynamicBackendParameters{}.MaxShaderStorageBlockSize);
}
return;
case GL_SUBGROUP_SIZE_KHR:
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR: {
GLint value = 0;
GetIntegerv(pname, &value);
params[0] = static_cast<GLint64>(value);
return;
}
default:
break;
}
GLint ints[4] = {}; GLint ints[4] = {};
GetIntegerv(pname, ints); GetIntegerv(pname, ints);
@@ -706,6 +728,7 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
const auto& rendererInfo = activeBackendObject->GetRendererInfo(); const auto& rendererInfo = activeBackendObject->GetRendererInfo();
const auto& dynamicParameters = activeBackendObject->GetDynamicParameters();
switch (pname) { switch (pname) {
case GL_ACTIVE_TEXTURE: case GL_ACTIVE_TEXTURE:
@@ -803,6 +826,18 @@ namespace MobileGL::MG_Impl::GLImpl {
case GL_COMPRESSED_TEXTURE_FORMATS: case GL_COMPRESSED_TEXTURE_FORMATS:
*params = 0; // compressed texture upload entrypoints are still unimplemented *params = 0; // compressed texture upload entrypoints are still unimplemented
break; break;
case GL_SUBGROUP_SIZE_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSize);
break;
case GL_SUBGROUP_SUPPORTED_STAGES_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedStages);
break;
case GL_SUBGROUP_SUPPORTED_FEATURES_KHR:
*params = static_cast<GLint>(dynamicParameters.SubgroupSupportedFeatures);
break;
case GL_SUBGROUP_QUAD_ALL_STAGES_KHR:
*params = dynamicParameters.SubgroupQuadOperationsInAllStages ? GL_TRUE : GL_FALSE;
break;
case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
*params = activeBackendObject->GetDynamicParameters().MaxComputeShaderStorageBlocks; *params = activeBackendObject->GetDynamicParameters().MaxComputeShaderStorageBlocks;
break; break;
@@ -1263,6 +1298,11 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = 0; *params = 0;
} }
break; break;
case GL_PARAMETER_BUFFER_BINDING_ARB: {
auto& obj = MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter).GetBoundObject();
*params = obj ? static_cast<GLint>(obj->GetExternalIndex()) : 0;
break;
}
case GL_POINT_FADE_THRESHOLD_SIZE: case GL_POINT_FADE_THRESHOLD_SIZE:
*params = 1; *params = 1;
break; break;
@@ -1283,7 +1323,8 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE; *params = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::ProgramPointSize) ? GL_TRUE : GL_FALSE;
break; break;
case GL_PROVOKING_VERTEX: case GL_PROVOKING_VERTEX:
*params = GL_LAST_VERTEX_CONVENTION; *params = static_cast<GLint>(
MG_Util::ConvertProvokingVertexModeToGLEnum(MG_State::pGLContext->GetProvokingVertexMode()));
break; break;
case GL_POINT_SIZE: case GL_POINT_SIZE:
*params = static_cast<GLint>(MG_State::pGLContext->GetPointSize()); *params = static_cast<GLint>(MG_State::pGLContext->GetPointSize());
@@ -798,6 +798,10 @@ namespace MobileGL::MG_Impl::GLImpl {
Uniformv_State<4>(location, count, value); Uniformv_State<4>(location, count, value);
} }
void Uniform1uiv_State(GLint location, GLsizei count, const GLuint* value) {
Uniformv_State<1>(location, count, value);
}
void UniformMatrix2fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { void UniformMatrix2fv_State(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
// For 2x2 matrices, we have 4 elements per matrix // For 2x2 matrices, we have 4 elements per matrix
// If transpose is GL_TRUE, we need to transpose the matrix data // If transpose is GL_TRUE, we need to transpose the matrix data
@@ -1353,7 +1357,6 @@ namespace MobileGL::MG_Impl::GLImpl {
GLuint v[] = {v0, v1, v2, v3}; GLuint v[] = {v0, v1, v2, v3};
Uniform4uiv(location, 1, v); Uniform4uiv(location, 1, v);
} }
void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) { void Uniform1fv(GLint location, GLsizei count, const GLfloat* value) {
Uniform1fv_State(location, count, value); Uniform1fv_State(location, count, value);
} }
@@ -320,6 +320,21 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_State::pGLContext->SetFrontFaceMode(frontFaceMode); MG_State::pGLContext->SetFrontFaceMode(frontFaceMode);
} }
void ProvokingVertex_State(GLenum mode) {
ProvokingVertexMode provokingVertexMode = MG_Util::ConvertGLEnumToProvokingVertexMode(mode);
if (provokingVertexMode == ProvokingVertexMode::Unknown) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "ProvokingVertex_State",
"Provoking vertex mode enum " +
MG_Util::ConvertProvokingVertexModeToString(provokingVertexMode) +
"(" + MG_Util::ConvertGLEnumToString(mode) + ") is not supported."));
return;
}
MG_State::pGLContext->SetProvokingVertexMode(provokingVertexMode);
}
void Enable_State(GLenum cap) { void Enable_State(GLenum cap) {
CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap); CapabilityInput capInput = MG_Util::ConvertGLEnumToCapabilityInput(cap);
if (capInput == CapabilityInput::Unknown) { if (capInput == CapabilityInput::Unknown) {
@@ -665,6 +680,10 @@ namespace MobileGL::MG_Impl::GLImpl {
FrontFace_State(mode); FrontFace_State(mode);
} }
void ProvokingVertex(GLenum mode) {
ProvokingVertex_State(mode);
}
void Enable(GLenum cap) { void Enable(GLenum cap) {
Enable_State(cap); Enable_State(cap);
} }
@@ -40,6 +40,7 @@ namespace MobileGL::MG_Impl::GLImpl {
GLboolean IsEnabled(GLenum cap); GLboolean IsEnabled(GLenum cap);
void Hint(GLenum target, GLenum mode); void Hint(GLenum target, GLenum mode);
void FrontFace(GLenum mode); void FrontFace(GLenum mode);
void ProvokingVertex(GLenum mode);
void Enable(GLenum cap); void Enable(GLenum cap);
void Disable(GLenum cap); void Disable(GLenum cap);
void DepthRange(GLclampd near_val, GLclampd far_val); void DepthRange(GLclampd near_val, GLclampd far_val);
+139 -207
View File
@@ -8,7 +8,7 @@
#include "GL_Sync.h" #include "GL_Sync.h"
#include "MG_State/GLState/Core.h" #include <MG_State/GLState/Core.h>
#include <MG_Backend/BackendObjects.h> #include <MG_Backend/BackendObjects.h>
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h> #include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
#include <MG_Util/BackendLoaders/OpenGL/Loader.h> #include <MG_Util/BackendLoaders/OpenGL/Loader.h>
@@ -16,232 +16,164 @@
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl {
namespace { namespace {
const MG_External::GLESFunctionsTable* TryGetDirectGLESFunctions(const char* funcName) { struct SyncObject {
GLenum Condition = GL_SYNC_GPU_COMMANDS_COMPLETE;
GLbitfield Flags = 0;
GLsync BackendHandle = nullptr;
};
UnorderedMap<GLsync, UniquePtr<SyncObject>> g_syncObjects;
void RecordSyncError(const char* funcName, ErrorCode code, String message) {
MG_State::pGLContext->RecordError(code,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, Move(message)));
}
const MG_External::GLESFunctionsTable* TryGetDirectGLESFunctions() {
auto* activeBackend = MG_Backend::pActiveBackendObject.get(); auto* activeBackend = MG_Backend::pActiveBackendObject.get();
if (!activeBackend) { if (!activeBackend) return nullptr;
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "No active backend object."));
return nullptr;
}
auto* directGLESBackend = auto* directGLESBackend =
dynamic_cast<MG_Backend::DirectGLES::BackendObject_DirectGLES*>(activeBackend); dynamic_cast<MG_Backend::DirectGLES::BackendObject_DirectGLES*>(activeBackend);
if (!directGLESBackend) { return directGLESBackend ? &directGLESBackend->GetGLESFunctions() : nullptr;
MG_State::pGLContext->RecordError( }
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, SyncObject* GetSyncObject(GLsync sync, const char* funcName) {
"Sync objects are only implemented for the DirectGLES backend.")); auto it = g_syncObjects.find(sync);
if (sync == nullptr || it == g_syncObjects.end()) {
RecordSyncError(funcName, ErrorCode::InvalidValue, "Sync object is not valid.");
return nullptr; return nullptr;
} }
return it->second.get();
return &directGLESBackend->GetGLESFunctions();
} }
} // namespace
Bool ValidateFenceSyncArgs(const char* funcName, GLenum condition, GLbitfield flags) {
if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName,
"condition must be GL_SYNC_GPU_COMMANDS_COMPLETE."));
return false;
}
if (flags != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "flags must be zero."));
return false;
}
return true;
}
Bool ValidateSyncHandle(const char* funcName, GLsync sync) {
if (sync != nullptr) {
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", funcName, "sync must be a valid non-null handle."));
return false;
}
}
GLsync FenceSync_Backend(GLenum condition, GLbitfield flags) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glFenceSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glFenceSync."));
return nullptr;
}
return glesFuncs->glFenceSync(condition, flags);
}
GLboolean IsSync_Backend(GLsync sync) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glIsSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glIsSync."));
return GL_FALSE;
}
return glesFuncs->glIsSync(sync);
}
GLenum ClientWaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glClientWaitSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glClientWaitSync."));
return GL_WAIT_FAILED;
}
return glesFuncs->glClientWaitSync(sync, flags, timeout);
}
void WaitSync_Backend(GLsync sync, GLbitfield flags, GLuint64 timeout) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glWaitSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glWaitSync."));
return;
}
glesFuncs->glWaitSync(sync, flags, timeout);
}
void GetSynciv_Backend(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glGetSynciv) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glGetSynciv."));
return;
}
glesFuncs->glGetSynciv(sync, pname, bufSize, length, values);
}
void DeleteSync_Backend(GLsync sync) {
const auto* glesFuncs = TryGetDirectGLESFunctions(__func__);
if (!glesFuncs || !glesFuncs->glDeleteSync) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Backend does not expose glDeleteSync."));
return;
}
glesFuncs->glDeleteSync(sync);
}
GLsync FenceSync_State(GLenum condition, GLbitfield flags) {
if (!ValidateFenceSyncArgs(__func__, condition, flags)) {
return nullptr;
}
return FenceSync_Backend(condition, flags);
}
GLboolean IsSync_State(GLsync sync) {
if (sync == nullptr) return GL_FALSE;
return IsSync_Backend(sync);
}
GLenum ClientWaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
(void)timeout;
if (!ValidateSyncHandle(__func__, sync)) {
return GL_WAIT_FAILED;
}
if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"flags contains unsupported bits."));
return GL_WAIT_FAILED;
}
return ClientWaitSync_Backend(sync, flags, timeout);
}
void WaitSync_State(GLsync sync, GLbitfield flags, GLuint64 timeout) {
if (!ValidateSyncHandle(__func__, sync)) {
return;
}
if (flags != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "flags must be zero."));
return;
}
if (timeout != GL_TIMEOUT_IGNORED) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "timeout must be GL_TIMEOUT_IGNORED."));
return;
}
WaitSync_Backend(sync, flags, timeout);
}
void GetSynciv_State(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
if (!ValidateSyncHandle(__func__, sync)) {
return;
}
if (bufSize < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "bufSize must be non-negative."));
return;
}
if (bufSize > 0 && values == nullptr) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"values must not be null when bufSize is positive."));
return;
}
switch (pname) {
case GL_OBJECT_TYPE:
case GL_SYNC_CONDITION:
case GL_SYNC_STATUS:
case GL_SYNC_FLAGS:
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Unsupported sync pname."));
return;
}
GetSynciv_Backend(sync, pname, bufSize, length, values);
}
void DeleteSync_State(GLsync sync) {
if (sync == nullptr) return;
DeleteSync_Backend(sync);
}
GLsync FenceSync(GLenum condition, GLbitfield flags) { GLsync FenceSync(GLenum condition, GLbitfield flags) {
return FenceSync_State(condition, flags); if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) {
RecordSyncError("FenceSync", ErrorCode::InvalidEnum, "Condition must be GL_SYNC_GPU_COMMANDS_COMPLETE.");
return nullptr;
}
if (flags != 0) {
RecordSyncError("FenceSync", ErrorCode::InvalidValue, "Flags must be zero.");
return nullptr;
}
auto syncObject = MakeUnique<SyncObject>();
syncObject->Condition = condition;
syncObject->Flags = flags;
if (const auto* glesFuncs = TryGetDirectGLESFunctions(); glesFuncs && glesFuncs->glFenceSync) {
syncObject->BackendHandle = glesFuncs->glFenceSync(condition, flags);
if (syncObject->BackendHandle == nullptr) {
return nullptr;
}
}
GLsync handle = reinterpret_cast<GLsync>(syncObject.get());
g_syncObjects[handle] = Move(syncObject);
return handle;
} }
GLboolean IsSync(GLsync sync) { GLboolean IsSync(GLsync sync) {
return IsSync_State(sync); return g_syncObjects.find(sync) != g_syncObjects.end() ? GL_TRUE : GL_FALSE;
} }
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
return ClientWaitSync_State(sync, flags, timeout); (void)timeout;
if ((flags & ~GL_SYNC_FLUSH_COMMANDS_BIT) != 0) {
RecordSyncError("ClientWaitSync", ErrorCode::InvalidValue,
"Flags can only contain GL_SYNC_FLUSH_COMMANDS_BIT.");
return GL_WAIT_FAILED;
}
auto* syncObject = GetSyncObject(sync, "ClientWaitSync");
if (!syncObject) return GL_WAIT_FAILED;
if (syncObject->BackendHandle != nullptr) {
if (const auto* glesFuncs = TryGetDirectGLESFunctions(); glesFuncs && glesFuncs->glClientWaitSync) {
return glesFuncs->glClientWaitSync(syncObject->BackendHandle, flags, timeout);
}
RecordSyncError("ClientWaitSync", ErrorCode::InvalidOperation, "Backend sync wait is unavailable.");
return GL_WAIT_FAILED;
}
return GL_ALREADY_SIGNALED;
} }
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
WaitSync_State(sync, flags, timeout); if (flags != 0) {
} RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Flags must be zero.");
return;
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { }
GetSynciv_State(sync, pname, bufSize, length, values); if (timeout != GL_TIMEOUT_IGNORED) {
RecordSyncError("WaitSync", ErrorCode::InvalidValue, "Timeout must be GL_TIMEOUT_IGNORED.");
return;
}
auto* syncObject = GetSyncObject(sync, "WaitSync");
if (!syncObject) return;
if (syncObject->BackendHandle != nullptr) {
if (const auto* glesFuncs = TryGetDirectGLESFunctions(); glesFuncs && glesFuncs->glWaitSync) {
glesFuncs->glWaitSync(syncObject->BackendHandle, flags, timeout);
return;
}
RecordSyncError("WaitSync", ErrorCode::InvalidOperation, "Backend sync wait is unavailable.");
}
} }
void DeleteSync(GLsync sync) { void DeleteSync(GLsync sync) {
DeleteSync_State(sync); if (sync == nullptr) return;
auto it = g_syncObjects.find(sync);
if (it == g_syncObjects.end()) {
RecordSyncError("DeleteSync", ErrorCode::InvalidValue, "Sync object is not valid.");
return;
}
if (it->second->BackendHandle != nullptr) {
if (const auto* glesFuncs = TryGetDirectGLESFunctions(); glesFuncs && glesFuncs->glDeleteSync) {
glesFuncs->glDeleteSync(it->second->BackendHandle);
}
}
g_syncObjects.erase(it);
}
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) {
if (bufSize < 0) {
RecordSyncError("GetSynciv", ErrorCode::InvalidValue, "bufSize must be non-negative.");
return;
}
if (bufSize > 0 && values == nullptr) {
RecordSyncError("GetSynciv", ErrorCode::InvalidValue,
"values must not be null when bufSize is positive.");
return;
}
auto* syncObject = GetSyncObject(sync, "GetSynciv");
if (!syncObject) return;
if (syncObject->BackendHandle != nullptr) {
if (const auto* glesFuncs = TryGetDirectGLESFunctions(); glesFuncs && glesFuncs->glGetSynciv) {
glesFuncs->glGetSynciv(syncObject->BackendHandle, pname, bufSize, length, values);
return;
}
}
GLint value = 0;
switch (pname) {
case GL_OBJECT_TYPE:
value = GL_SYNC_FENCE;
break;
case GL_SYNC_STATUS:
value = GL_SIGNALED;
break;
case GL_SYNC_CONDITION:
value = static_cast<GLint>(syncObject->Condition);
break;
case GL_SYNC_FLAGS:
value = static_cast<GLint>(syncObject->Flags);
break;
default:
RecordSyncError("GetSynciv", ErrorCode::InvalidEnum, std::format("Invalid pname enum: 0x{:X}", pname));
return;
}
if (length) {
*length = bufSize > 0 && values ? 1 : 0;
}
if (bufSize > 0 && values) {
values[0] = value;
}
} }
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
+2 -2
View File
@@ -12,8 +12,8 @@
namespace MobileGL::MG_Impl::GLImpl { namespace MobileGL::MG_Impl::GLImpl {
GLsync FenceSync(GLenum condition, GLbitfield flags); GLsync FenceSync(GLenum condition, GLbitfield flags);
GLboolean IsSync(GLsync sync); GLboolean IsSync(GLsync sync);
void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout); GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values); void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout);
void DeleteSync(GLsync sync); void DeleteSync(GLsync sync);
void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
} // namespace MobileGL::MG_Impl::GLImpl } // namespace MobileGL::MG_Impl::GLImpl
+575 -69
View File
@@ -46,6 +46,214 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
} // namespace } // namespace
const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByName(GLuint texture, const char* caller) {
if (texture == 0 || !TextureImpl::ValidateTextureName(texture, true)) return nullTextureObject;
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
if (!TextureImpl::ValidateTextureObject(textureObject)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
std::format("Texture object {} does not exist.", texture)));
return nullTextureObject;
}
return textureObject;
}
TextureUploadTarget GetPrimaryUploadTarget(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject) {
if (!textureObject) return TextureUploadTarget::Unknown;
const auto& uploadTargets = textureObject->GetUploadTargets();
return uploadTargets.empty() ? TextureUploadTarget::Unknown : uploadTargets[0];
}
void TextureParameterObject_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
GLint param, const char* caller) {
if (!textureObject) return;
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
break;
case GL_TEXTURE_MIN_FILTER:
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(param));
break;
case GL_TEXTURE_MIN_LOD: {
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
break;
}
case GL_TEXTURE_MAX_LOD: {
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
break;
}
case GL_TEXTURE_BASE_LEVEL:
textureObject->SetBaseLevel(param);
break;
case GL_TEXTURE_MAX_LEVEL:
textureObject->SetMaxLevel(param);
break;
case GL_TEXTURE_SWIZZLE_R:
case GL_TEXTURE_SWIZZLE_G:
case GL_TEXTURE_SWIZZLE_B:
case GL_TEXTURE_SWIZZLE_A: {
auto swizzleParam = MG_Util::ConvertGLEnumPnameToTextureSwizzleParam(pname);
auto swizzleValue = MG_Util::ConvertGLEnumToTextureSwizzleParam(param);
textureObject->SetSwizzleParam(swizzleParam, swizzleValue);
break;
}
case GL_TEXTURE_WRAP_S:
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_WRAP_T:
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_WRAP_R:
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_COMPARE_MODE:
textureObject->GetSamplerObject()->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(param));
break;
case GL_TEXTURE_COMPARE_FUNC:
textureObject->GetSamplerObject()->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(param));
break;
case GL_TEXTURE_LOD_BIAS:
textureObject->GetSamplerObject()->SetLodBias((GLfloat)param);
break;
case GL_GENERATE_MIPMAP:
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != GL_FALSE);
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
return;
}
}
void TextureParameterObjectf_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLenum pname,
GLfloat param, const char* caller) {
if (!textureObject) return;
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode((GLenum)param));
break;
case GL_TEXTURE_MIN_FILTER:
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode((GLenum)param));
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode((GLenum)param));
break;
case GL_TEXTURE_MIN_LOD: {
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
break;
}
case GL_TEXTURE_MAX_LOD: {
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
break;
}
case GL_TEXTURE_BASE_LEVEL:
textureObject->SetBaseLevel((Uint)param);
break;
case GL_TEXTURE_MAX_LEVEL:
textureObject->SetMaxLevel((Uint)param);
break;
case GL_TEXTURE_WRAP_S:
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
break;
case GL_TEXTURE_WRAP_T:
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
break;
case GL_TEXTURE_WRAP_R:
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode((GLenum)param));
break;
case GL_TEXTURE_COMPARE_MODE:
textureObject->GetSamplerObject()->SetCompareMode(
MG_Util::ConvertGLEnumToSamplerCompareMode((GLenum)param));
break;
case GL_TEXTURE_COMPARE_FUNC:
textureObject->GetSamplerObject()->SetSamplerCompareFunc(
MG_Util::ConvertGLEnumToSamplerCompareFunc((GLenum)param));
break;
case GL_TEXTURE_LOD_BIAS:
textureObject->GetSamplerObject()->SetLodBias(param);
break;
case GL_GENERATE_MIPMAP:
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != 0.0f);
break;
case GL_DEPTH_STENCIL_TEXTURE_MODE:
if (param != GL_DEPTH_COMPONENT && param != GL_STENCIL_INDEX) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
"Invalid GL_DEPTH_STENCIL_TEXTURE_MODE value."));
}
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
return;
}
}
void GetTextureParameterObjectiv_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
GLenum pname, GLint* params, const char* caller) {
if (!textureObject || !params) return;
switch (pname) {
case GL_TEXTURE_MAG_FILTER:
*params = (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(textureObject->GetSamplerObject()->GetMagFilter(),
SamplerMipmapMode::None);
break;
case GL_TEXTURE_MIN_FILTER:
*params = (GLint)MG_Util::ConvertSamplerFilterModeToGLEnum(
textureObject->GetSamplerObject()->GetMinFilter(), textureObject->GetSamplerObject()->GetMipmapMode());
break;
case GL_TEXTURE_MIN_LOD:
*params = static_cast<GLint>(textureObject->GetSamplerObject()->GetMinLod());
break;
case GL_TEXTURE_MAX_LOD:
*params = static_cast<GLint>(textureObject->GetSamplerObject()->GetMaxLod());
break;
case GL_TEXTURE_BASE_LEVEL:
*params = static_cast<GLint>(textureObject->GetLevelRange().x());
break;
case GL_TEXTURE_MAX_LEVEL:
*params = static_cast<GLint>(textureObject->GetLevelRange().y());
break;
case GL_TEXTURE_WRAP_S:
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapS());
break;
case GL_TEXTURE_WRAP_T:
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapT());
break;
case GL_TEXTURE_WRAP_R:
*params = (GLint)MG_Util::ConvertSamplerWrapModeToGLEnum(textureObject->GetSamplerObject()->GetWrapR());
break;
case GL_TEXTURE_COMPARE_MODE:
*params =
(GLint)MG_Util::ConvertSamplerCompareModeToGLEnum(textureObject->GetSamplerObject()->GetCompareMode());
break;
case GL_TEXTURE_COMPARE_FUNC:
*params = (GLint)MG_Util::ConvertSamplerCompareFuncToGLEnum(
textureObject->GetSamplerObject()->GetSamplerCompareFunc());
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
"pname is not a valid texture parameter."));
return;
}
}
const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByTarget( const SharedPtr<MG_State::GLState::ITextureObject>& GetTextureObjectByTarget(
TextureUploadTarget textureUploadTarget, TextureTarget textureTarget) { TextureUploadTarget textureUploadTarget, TextureTarget textureTarget) {
if (TextureImpl::IsProxyTextureTarget(textureUploadTarget)) { if (TextureImpl::IsProxyTextureTarget(textureUploadTarget)) {
@@ -172,7 +380,7 @@ namespace MobileGL::MG_Impl::GLImpl {
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType); const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureInternalFormat, texturePixelDataType);
const SizeT srcRowSize = static_cast<SizeT>(width) * internalBpp; const SizeT srcRowSize = static_cast<SizeT>(width) * internalBpp;
const SizeT srcStride = (srcRowSize + unpackParams.Alignment - 1) & ~(unpackParams.Alignment - 1); const SizeT srcStride = srcRowSize;
const SizeT destRowSize = static_cast<SizeT>(texelSize.x()) * internalBpp; const SizeT destRowSize = static_cast<SizeT>(texelSize.x()) * internalBpp;
if (xoffset + width > static_cast<GLsizei>(texelSize.x()) || if (xoffset + width > static_cast<GLsizei>(texelSize.x()) ||
@@ -295,72 +503,7 @@ namespace MobileGL::MG_Impl::GLImpl {
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget); auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
if (!textureObject) return; if (!textureObject) return;
switch (pname) { TextureParameterObject_State(textureObject, pname, param, __func__);
case GL_TEXTURE_MAG_FILTER:
textureObject->GetSamplerObject()->SetMagFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
break;
case GL_TEXTURE_MIN_FILTER:
textureObject->GetSamplerObject()->SetMinFilter(MG_Util::ConvertGLEnumToSamplerFilterMode(param));
textureObject->GetSamplerObject()->SetMipmapMode(MG_Util::ConvertGLEnumToSamplerMipmapMode(param));
break;
case GL_TEXTURE_MIN_LOD: {
Float maxLod = textureObject->GetSamplerObject()->GetMaxLod();
textureObject->GetSamplerObject()->SetLodRange(param, maxLod);
break;
}
case GL_TEXTURE_MAX_LOD: {
Float minLod = textureObject->GetSamplerObject()->GetMinLod();
textureObject->GetSamplerObject()->SetLodRange(minLod, param);
break;
}
case GL_TEXTURE_BASE_LEVEL:
textureObject->SetBaseLevel(param);
break;
case GL_TEXTURE_MAX_LEVEL:
textureObject->SetMaxLevel(param);
break;
case GL_TEXTURE_SWIZZLE_R:
case GL_TEXTURE_SWIZZLE_G:
case GL_TEXTURE_SWIZZLE_B:
case GL_TEXTURE_SWIZZLE_A: {
auto swizzleParam = MG_Util::ConvertGLEnumPnameToTextureSwizzleParam(pname);
auto swizzleValue = MG_Util::ConvertGLEnumToTextureSwizzleParam(param);
textureObject->SetSwizzleParam(swizzleParam, swizzleValue);
break;
}
case GL_TEXTURE_WRAP_S:
textureObject->GetSamplerObject()->SetWrapS(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_WRAP_T:
textureObject->GetSamplerObject()->SetWrapT(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_WRAP_R:
textureObject->GetSamplerObject()->SetWrapR(MG_Util::ConvertGLEnumToSamplerWrapMode(param));
break;
case GL_TEXTURE_COMPARE_MODE:
textureObject->GetSamplerObject()->SetCompareMode(MG_Util::ConvertGLEnumToSamplerCompareMode(param));
break;
case GL_TEXTURE_COMPARE_FUNC:
textureObject->GetSamplerObject()->SetSamplerCompareFunc(MG_Util::ConvertGLEnumToSamplerCompareFunc(param));
break;
case GL_TEXTURE_LOD_BIAS:
textureObject->GetSamplerObject()->SetLodBias((GLfloat)param);
break;
case GL_GENERATE_MIPMAP:
g_autoGenerateMipmapByTextureId[textureObject->GetExternalIndex()] = (param != GL_FALSE);
break;
case GL_TEXTURE_SWIZZLE_RGBA:
// Not supported in this function
case GL_TEXTURE_BORDER_COLOR:
// Not supported in this function
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", __func__,
std::format("pname {} is not a valid texture parameter.", MG_Util::ConvertGLEnumToString(pname))));
return;
}
} }
// Quick and dirty TexParameter*v implementation to make NeoForge happy. // Quick and dirty TexParameter*v implementation to make NeoForge happy.
@@ -1275,7 +1418,7 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
// ======================= Processing ================================ // ======================= Processing ================================
static thread_local Vector<Uint> textureNames; Vector<Uint> textureNames;
MG_State::pGLContext->GenTextureNames(n, textureNames); MG_State::pGLContext->GenTextureNames(n, textureNames);
Memcpy(textures, textureNames.data(), n * sizeof(GLuint)); Memcpy(textures, textureNames.data(), n * sizeof(GLuint));
} }
@@ -1591,7 +1734,361 @@ namespace MobileGL::MG_Impl::GLImpl {
return true; return true;
} }
void CopyTextureImageToClientOrPBO_State(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
TextureUploadTarget textureUploadTarget, GLint level, GLenum format,
GLenum type, GLsizei bufSize, void* pixels, const char* caller) {
if (!textureObject) return;
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Texture storage is not mipmap-backed."));
return;
}
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Texture level is out of range."));
return;
}
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level);
const void* src = textureMipmapObject->MapMipmapData(textureUploadTarget, level);
if (!src) return;
SizeT packedSize = 0;
void* packedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataPack(
src, MG_State::pGLContext->GetPixelStoreParameters(false), textureObject->GetFormat(), texturePixelDataType,
textureInputFormat, texturePixelDataType, texelSize, false, packedSize);
if (!packedPixels || packedSize == 0) {
if (packedPixels) free(packedPixels);
return;
}
if (bufSize >= 0 && static_cast<SizeT>(bufSize) < packedSize) {
free(packedPixels);
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Destination buffer is too small."));
return;
}
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
const SizeT offset = reinterpret_cast<SizeT>(pixels);
if (offset + packedSize > pixelPackBufferObject->GetSize()) {
free(packedPixels);
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "Pixel pack buffer is too small."));
return;
}
pixelPackBufferObject->UploadSubData({packedPixels, packedSize}, offset);
} else if (pixels) {
Memcpy(pixels, packedPixels, packedSize);
}
free(packedPixels);
}
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
void CreateTextures(GLenum target, GLsizei n, GLuint* textures) {
if (n < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "n must be non-negative."));
return;
}
if (n > 0 && !textures) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture output pointer cannot be null."));
return;
}
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
if (!TextureImpl::ValidateTextureTarget(textureTarget)) return;
Vector<Uint> textureNames;
MG_State::pGLContext->GenTextureNames(n, textureNames);
for (GLsizei i = 0; i < n; ++i) {
textures[i] = textureNames[i];
MG_State::pGLContext->CreateTextureObject(textureNames[i], textureTarget);
}
}
void TextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
if (levels < 1) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "levels must be positive."));
return;
}
if (!TextureImpl::ValidateTextureSizeRange(width, height, 1)) return;
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
textureInternalFormat = MG_Util::ConvertInternalFormatToSized(textureInternalFormat, TextureInputFormat::RGBA,
TexturePixelDataType::UnsignedByte);
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
return;
}
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
GLenum realInternalFormat = internalformat;
GLenum realFormat = GL_RGBA;
GLenum realType = GL_UNSIGNED_BYTE;
MG_Util::TextureFormatProcessor::NormalizePixelFormat(
MG_Util::ConvertTextureInternalFormatToGLEnum(textureInternalFormat), PixelFormatNormalizeOptionBit::None,
&realInternalFormat, &realFormat, &realType);
const SizeT bytesPerPixel = MG_Util::GetInternalBytesPerPixel(
textureInternalFormat, MG_Util::ConvertGLEnumToTexturePixelDataType(realType));
textureObject->SetInternalFormat(textureInternalFormat);
for (GLsizei level = 0; level < levels; ++level) {
const GLsizei levelWidth = std::max<GLsizei>(1, width >> level);
const GLsizei levelHeight = std::max<GLsizei>(1, height >> level);
const SizeT byteSize = static_cast<SizeT>(levelWidth) * static_cast<SizeT>(levelHeight) * bytesPerPixel;
textureMipmapObject->AllocateStorage(textureUploadTarget, level, {{levelWidth, levelHeight, 1}, byteSize});
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, false);
}
}
void TextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLenum type, const void* pixels) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
TextureInputFormat textureInputFormat = MG_Util::ConvertGLEnumToTextureInputFormat(format);
TexturePixelDataType texturePixelDataType = MG_Util::ConvertGLEnumToTexturePixelDataType(type);
if (!TextureImpl::ValidateTexturePixelDataType(texturePixelDataType)) return;
if (!TextureImpl::ValidateTextureInputFormat(textureInputFormat)) return;
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
if (!TextureImpl::ValidateTextureSizeRange(width, height, 1)) return;
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
return;
}
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
if (!TextureImpl::ValidateTextureInternalFormatCompatibleWithInput(textureInputFormat, textureObject->GetFormat(),
texturePixelDataType))
return;
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level is out of range."));
return;
}
if (!TextureImpl::ValidateTextureSubImageOffsets(textureObject, xoffset, width, yoffset, height)) return;
const void* originalPixels = pixels;
const auto& pixelUnpackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelUnpack).GetBoundObject();
if (pixelUnpackBufferObject) {
originalPixels = reinterpret_cast<const char*>(pixelUnpackBufferObject->GetDataReadOnly()->data()) +
reinterpret_cast<SizeT>(pixels);
}
if (!originalPixels) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"No data supplied from pixels parameter and no PBO bound."));
return;
}
SizeT inputSize = 0;
void* processedPixels = MG_Util::PixelStoreProcessor::ProcessTexturePixelsDataUnpack(
originalPixels, MG_State::pGLContext->GetPixelStoreParameters(true), textureObject->GetFormat(),
textureInputFormat, texturePixelDataType, {width, height, 1}, false, inputSize);
if (!processedPixels || inputSize == 0) {
if (processedPixels) free(processedPixels);
return;
}
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level);
const SizeT internalBpp = MG_Util::GetInternalBytesPerPixel(textureObject->GetFormat(), texturePixelDataType);
const SizeT srcRowSize = static_cast<SizeT>(width) * internalBpp;
const SizeT destRowSize = static_cast<SizeT>(texelSize.x()) * internalBpp;
const auto* srcData = static_cast<const Uint8*>(processedPixels);
Uint8* destData = static_cast<Uint8*>(textureMipmapObject->MapMipmapData(textureUploadTarget, level));
if (destData) {
for (GLsizei y = 0; y < height; ++y) {
const SizeT destRowOffset = static_cast<SizeT>(yoffset + y) * destRowSize +
static_cast<SizeT>(xoffset) * internalBpp;
const SizeT srcRowOffset = static_cast<SizeT>(y) * srcRowSize;
Memcpy(destData + destRowOffset, srcData + srcRowOffset, srcRowSize);
}
textureMipmapObject->MarkStorageDirty(textureUploadTarget, level, true);
}
free(processedPixels);
}
void TextureParameteri(GLuint texture, GLenum pname, GLint param) {
auto textureObject = GetTextureObjectByName(texture, __func__);
TextureParameterObject_State(textureObject, pname, param, __func__);
}
void TextureParameterf(GLuint texture, GLenum pname, GLfloat param) {
auto textureObject = GetTextureObjectByName(texture, __func__);
TextureParameterObjectf_State(textureObject, pname, param, __func__);
}
void TextureParameteriv(GLuint texture, GLenum pname, const GLint* params) {
if (!params) return;
if (pname == GL_TEXTURE_SWIZZLE_RGBA) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
Vec4<TextureSwizzleParam> swizzleParams;
for (int i = 0; i < 4; i++) {
swizzleParams[i] = MG_Util::ConvertGLEnumToTextureSwizzleParam(static_cast<GLint>(params[i]));
if (TextureSwizzleParam::Unknown == swizzleParams[i]) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "`params` is not valid."));
return;
}
}
textureObject->SetSwizzleParamRGBA(swizzleParams);
return;
}
TextureParameteri(texture, pname, *params);
}
void BindTextureUnit(GLuint unit, GLuint texture) {
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture unit is out of range."));
return;
}
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(static_cast<Int>(unit));
if (texture == 0) {
for (auto& slot : textureUnit.GetAllBindingSlots()) {
slot.Bind(nullptr);
}
return;
}
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
textureUnit.GetBindingSlot(textureObject->GetTarget()).Bind(textureObject);
}
void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
const auto uploadTarget = GetPrimaryUploadTarget(textureObject);
if (MG_Backend::pActiveBackendObject != nullptr &&
MG_Backend::pActiveBackendObject->GetBackendType() == BackendType::DirectVulkan &&
MG_Backend::gBackendFunctionsTable.GL.GetTextureImage != nullptr) {
MG_Backend::gBackendFunctionsTable.GL.GetTextureImage(textureObject, uploadTarget, level, format, type,
bufSize, pixels);
return;
}
CopyTextureImageToClientOrPBO_State(textureObject, uploadTarget, level, format, type, bufSize, pixels,
__func__);
}
void GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject) return;
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0 || depth < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture sub-image range is invalid."));
return;
}
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture storage is not mipmap-backed."));
return;
}
const auto uploadTarget = GetPrimaryUploadTarget(textureObject);
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
if (static_cast<Uint>(level) >= textureMipmapObject->GetMipmapLevelCount()) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level is out of range."));
return;
}
const auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, static_cast<Uint>(level));
const Bool isFullLevelRead = xoffset == 0 && yoffset == 0 && zoffset == 0 &&
width == texelSize.x() && height == texelSize.y() &&
depth == texelSize.z();
if (!isFullLevelRead) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Partial texture sub-image readback is not implemented yet."));
return;
}
GetTextureImage(texture, level, format, type, bufSize, pixels);
}
void GetTextureParameteriv(GLuint texture, GLenum pname, GLint* params) {
auto textureObject = GetTextureObjectByName(texture, __func__);
GetTextureParameterObjectiv_State(textureObject, pname, params, __func__);
}
void GetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params) {
auto textureObject = GetTextureObjectByName(texture, __func__);
if (!textureObject || !params) return;
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
if (textureObject->GetStorageType() != TextureStorageType::Mipmap) return;
auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
switch (pname) {
case GL_TEXTURE_WIDTH:
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).x();
break;
case GL_TEXTURE_HEIGHT:
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).y();
break;
case GL_TEXTURE_DEPTH:
*params = textureMipmapObject->GetMipmapTexelSize(textureUploadTarget, level).z();
break;
case GL_TEXTURE_INTERNAL_FORMAT:
*params = (GLint)MG_Util::ConvertTextureInternalFormatToGLEnum(textureObject->GetFormat());
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"pname is not a valid texture level parameter."));
return;
}
}
void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, void BindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access,
GLenum format) { GLenum format) {
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) { if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
@@ -1650,7 +2147,16 @@ namespace MobileGL::MG_Impl::GLImpl {
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) { void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) {
if (!GetTexImage_State(target, level, format, type, pixels)) return; if (!GetTexImage_State(target, level, format, type, pixels)) return;
GetTexImage_Backend(target, level, format, type, pixels); if (MG_Backend::gBackendFunctionsTable.GL.GetTexImage != nullptr) {
GetTexImage_Backend(target, level, format, type, pixels);
return;
}
TextureUploadTarget textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
const auto& textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
CopyTextureImageToClientOrPBO_State(textureObject, textureUploadTarget, level, format, type, -1, pixels,
__func__);
} }
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
@@ -15,6 +15,19 @@ namespace MobileGL::MG_Impl::GLImpl {
GLenum format); GLenum format);
void GenerateMipmap(GLenum target); void GenerateMipmap(GLenum target);
void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels); void GetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
void CreateTextures(GLenum target, GLsizei n, GLuint* textures);
void TextureStorage2D(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void TextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLenum type, const void* pixels);
void TextureParameterf(GLuint texture, GLenum pname, GLfloat param);
void TextureParameteri(GLuint texture, GLenum pname, GLint param);
void TextureParameteriv(GLuint texture, GLenum pname, const GLint* params);
void BindTextureUnit(GLuint unit, GLuint texture);
void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
void GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
void GetTextureParameteriv(GLuint texture, GLenum pname, GLint* params);
void GetTextureLevelParameteriv(GLuint texture, GLint level, GLenum pname, GLint* params);
void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels);
void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
@@ -8,6 +8,7 @@
#include "GL_VertexArray.h" #include "GL_VertexArray.h"
#include "Validators.h" #include "Validators.h"
#include <MG_Impl/GLImpl/Buffer/Validators.h>
#include <MG_State/GLState/Core.h> #include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h> #include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToMG/DataTypeConverter.h> #include <MG_Util/Converters/GLToMG/DataTypeConverter.h>
@@ -69,6 +70,28 @@ namespace MobileGL::MG_Impl::GLImpl {
} }
} // namespace } // namespace
SharedPtr<MG_State::GLState::VertexArrayObject> GetNamedVertexArrayObject_State(GLuint vaobj,
const char* caller) {
if (!VertexArrayImpl::ValidateVertexArrayName(vaobj)) return nullptr;
if (!VertexArrayImpl::ValidateVertexArrayObject(vaobj)) return nullptr;
return MG_State::pGLContext->GetVertexArrayObject(vaobj);
}
SharedPtr<MG_State::GLState::BufferObject> GetVertexArrayBufferObject_State(GLuint buffer, const char* caller) {
if (!BufferImpl::ValidateBufferName(buffer, true)) return nullptr;
if (buffer == 0) return nullptr;
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
if (!bufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
std::format("Buffer object {} does not exist.", buffer)));
return nullptr;
}
return bufferObject;
}
void DisableVertexAttribArray_State(GLuint index) { void DisableVertexAttribArray_State(GLuint index) {
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return; if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
@@ -194,11 +217,96 @@ namespace MobileGL::MG_Impl::GLImpl {
return; return;
} }
static thread_local Vector<Uint> vaos; Vector<Uint> vaos;
MG_State::pGLContext->GenVertexArrayNames(n, vaos); MG_State::pGLContext->GenVertexArrayNames(n, vaos);
Memcpy(arrays, vaos.data(), n * sizeof(GLuint)); Memcpy(arrays, vaos.data(), n * sizeof(GLuint));
} }
void CreateVertexArrays_State(GLsizei n, GLuint* arrays) {
if (n < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "CreateVertexArrays_State", "n must be non-negative."));
return;
}
Vector<Uint> vaos;
MG_State::pGLContext->GenVertexArrayNames(n, vaos);
for (GLsizei i = 0; i < n; ++i) {
MG_State::pGLContext->CreateVertexArrayObject(vaos[i]);
arrays[i] = vaos[i];
}
}
void DisableVertexArrayAttrib_State(GLuint vaobj, GLuint index) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "DisableVertexArrayAttrib_State");
if (!vao) return;
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
vao->DisableAttribute(index);
}
void EnableVertexArrayAttrib_State(GLuint vaobj, GLuint index) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "EnableVertexArrayAttrib_State");
if (!vao) return;
if (!VertexArrayImpl::ValidateVertexAttributeIndex(index)) return;
vao->EnableAttribute(index);
}
void VertexArrayElementBuffer_State(GLuint vaobj, GLuint buffer) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayElementBuffer_State");
if (!vao) return;
auto bufferObject = GetVertexArrayBufferObject_State(buffer, "VertexArrayElementBuffer_State");
if (buffer != 0 && !bufferObject) return;
vao->GetIndexBufferBindingSlot().Bind(bufferObject);
}
void VertexArrayVertexBuffer_State(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset,
GLsizei stride) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayVertexBuffer_State");
if (!vao) return;
if (!VertexArrayImpl::ValidateVertexAttributeIndex(bindingindex)) return;
if (offset < 0 || stride < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "VertexArrayVertexBuffer_State",
"offset and stride must be non-negative."));
return;
}
auto bufferObject = GetVertexArrayBufferObject_State(buffer, "VertexArrayVertexBuffer_State");
if (buffer != 0 && !bufferObject) return;
const auto& attr = vao->GetAttribute(bindingindex);
vao->SetAttributeFormat(bindingindex, attr.Size, attr.Type, attr.Normalized, stride, static_cast<SizeT>(offset),
attr.IsInteger);
vao->BindAttributeBuffer(bindingindex, bufferObject);
}
void VertexArrayAttribFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
GLboolean normalized, GLuint relativeoffset) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribFormat_State");
if (!vao) return;
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
const auto& attr = vao->GetAttribute(attribindex);
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
vao->SetAttributeFormat(attribindex, size, dataType, normalized, attr.Stride, relativeoffset, false);
}
void VertexArrayAttribIFormat_State(GLuint vaobj, GLuint attribindex, GLint size, GLenum type,
GLuint relativeoffset) {
auto vao = GetNamedVertexArrayObject_State(vaobj, "VertexArrayAttribIFormat_State");
if (!vao) return;
if (!VertexArrayImpl::ValidateVertexAttributeIndex(attribindex)) return;
DataType dataType = MG_Util::ConvertGLEnumToDataType(type);
const auto& attr = vao->GetAttribute(attribindex);
if (!VertexArrayImpl::ValidateVertexAttribPointerParams(attribindex, size, dataType, attr.Stride)) return;
vao->SetAttributeFormat(attribindex, size, dataType, false, attr.Stride, relativeoffset, true);
}
GLboolean IsVertexArray_State(GLuint array) { GLboolean IsVertexArray_State(GLuint array) {
if (array == 0) return GL_FALSE; if (array == 0) return GL_FALSE;
return MG_State::pGLContext->ValidateVertexArrayObject(array) ? GL_TRUE : GL_FALSE; return MG_State::pGLContext->ValidateVertexArrayObject(array) ? GL_TRUE : GL_FALSE;
@@ -498,6 +606,38 @@ namespace MobileGL::MG_Impl::GLImpl {
GLint signedParams[4] = {}; GLint signedParams[4] = {};
GetVertexAttribiv(index, pname, signedParams); GetVertexAttribiv(index, pname, signedParams);
params[0] = static_cast<GLuint>(signedParams[0]); params[0] = static_cast<GLuint>(signedParams[0]);
params[1] = static_cast<GLuint>(signedParams[1]);
params[2] = static_cast<GLuint>(signedParams[2]);
params[3] = static_cast<GLuint>(signedParams[3]);
}
void CreateVertexArrays(GLsizei n, GLuint* arrays) {
CreateVertexArrays_State(n, arrays);
}
void DisableVertexArrayAttrib(GLuint vaobj, GLuint index) {
DisableVertexArrayAttrib_State(vaobj, index);
}
void EnableVertexArrayAttrib(GLuint vaobj, GLuint index) {
EnableVertexArrayAttrib_State(vaobj, index);
}
void VertexArrayElementBuffer(GLuint vaobj, GLuint buffer) {
VertexArrayElementBuffer_State(vaobj, buffer);
}
void VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) {
VertexArrayVertexBuffer_State(vaobj, bindingindex, buffer, offset, stride);
}
void VertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
GLuint relativeoffset) {
VertexArrayAttribFormat_State(vaobj, attribindex, size, type, normalized, relativeoffset);
}
void VertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) {
VertexArrayAttribIFormat_State(vaobj, attribindex, size, type, relativeoffset);
} }
void VertexAttribDivisor(GLuint index, GLuint divisor) { void VertexAttribDivisor(GLuint index, GLuint divisor) {
@@ -31,6 +31,14 @@ namespace MobileGL::MG_Impl::GLImpl {
void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer); void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer);
void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params); void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params);
void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params); void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params);
void CreateVertexArrays(GLsizei n, GLuint* arrays);
void DisableVertexArrayAttrib(GLuint vaobj, GLuint index);
void EnableVertexArrayAttrib(GLuint vaobj, GLuint index);
void VertexArrayElementBuffer(GLuint vaobj, GLuint buffer);
void VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
void VertexArrayAttribFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized,
GLuint relativeoffset);
void VertexArrayAttribIFormat(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
void VertexAttribDivisor(GLuint index, GLuint divisor); void VertexAttribDivisor(GLuint index, GLuint divisor);
GLboolean IsVertexArray(GLuint array); GLboolean IsVertexArray(GLuint array);
void DisableVertexAttribArray(GLuint index); void DisableVertexAttribArray(GLuint index);
+17
View File
@@ -321,22 +321,39 @@ namespace MobileGL::MG_Impl {
GETPROC(glClearBufferfi, name); GETPROC(glClearBufferfi, name);
GETPROC(glGetStringi, name); GETPROC(glGetStringi, name);
GETPROC(glIsRenderbuffer, name); GETPROC(glIsRenderbuffer, name);
GETPROC(glIsRenderbufferEXT, name);
GETPROC(glBindRenderbuffer, name); GETPROC(glBindRenderbuffer, name);
GETPROC(glBindRenderbufferEXT, name);
GETPROC(glDeleteRenderbuffers, name); GETPROC(glDeleteRenderbuffers, name);
GETPROC(glDeleteRenderbuffersEXT, name);
GETPROC(glGenRenderbuffers, name); GETPROC(glGenRenderbuffers, name);
GETPROC(glGenRenderbuffersEXT, name);
GETPROC(glRenderbufferStorage, name); GETPROC(glRenderbufferStorage, name);
GETPROC(glRenderbufferStorageEXT, name);
GETPROC(glGetRenderbufferParameteriv, name); GETPROC(glGetRenderbufferParameteriv, name);
GETPROC(glGetRenderbufferParameterivEXT, name);
GETPROC(glIsFramebuffer, name); GETPROC(glIsFramebuffer, name);
GETPROC(glIsFramebufferEXT, name);
GETPROC(glBindFramebuffer, name); GETPROC(glBindFramebuffer, name);
GETPROC(glBindFramebufferEXT, name);
GETPROC(glDeleteFramebuffers, name); GETPROC(glDeleteFramebuffers, name);
GETPROC(glDeleteFramebuffersEXT, name);
GETPROC(glGenFramebuffers, name); GETPROC(glGenFramebuffers, name);
GETPROC(glGenFramebuffersEXT, name);
GETPROC(glCheckFramebufferStatus, name); GETPROC(glCheckFramebufferStatus, name);
GETPROC(glCheckFramebufferStatusEXT, name);
GETPROC(glFramebufferTexture1D, name); GETPROC(glFramebufferTexture1D, name);
GETPROC(glFramebufferTexture1DEXT, name);
GETPROC(glFramebufferTexture2D, name); GETPROC(glFramebufferTexture2D, name);
GETPROC(glFramebufferTexture2DEXT, name);
GETPROC(glFramebufferTexture3D, name); GETPROC(glFramebufferTexture3D, name);
GETPROC(glFramebufferTexture3DEXT, name);
GETPROC(glFramebufferRenderbuffer, name); GETPROC(glFramebufferRenderbuffer, name);
GETPROC(glFramebufferRenderbufferEXT, name);
GETPROC(glGetFramebufferAttachmentParameteriv, name); GETPROC(glGetFramebufferAttachmentParameteriv, name);
GETPROC(glGetFramebufferAttachmentParameterivEXT, name);
GETPROC(glGenerateMipmap, name); GETPROC(glGenerateMipmap, name);
GETPROC(glGenerateMipmapEXT, name);
GETPROC(glBlitFramebuffer, name); GETPROC(glBlitFramebuffer, name);
GETPROC(glRenderbufferStorageMultisample, name); GETPROC(glRenderbufferStorageMultisample, name);
GETPROC(glFramebufferTextureLayer, name); GETPROC(glFramebufferTextureLayer, name);
@@ -18,19 +18,41 @@ namespace MobileGL::MG_State::GLState {
} }
void BufferObject::Resize(SizeT size) { void BufferObject::Resize(SizeT size) {
ReleaseMemory();
m_size = size; m_size = size;
m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve m_dataPtr->reserve(std::bit_ceil(size)); // power-of-2 reserve
m_dataPtr->resize(size); m_dataPtr->resize(size);
m_isImmutableStorage = false;
m_storageFlags = 0;
m_change.Bits |= BufferChangeBits::DirtyBit; m_change.Bits |= BufferChangeBits::DirtyBit;
m_change.Bits |= BufferChangeBits::PreferReallocationBit; m_change.Bits |= BufferChangeBits::PreferReallocationBit;
++m_changeSerial; ++m_changeSerial;
} }
void BufferObject::AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags) {
ReleaseMemory();
m_size = size;
m_dataPtr->reserve(std::bit_ceil(size));
m_dataPtr->resize(size);
if (data) {
Memcpy(m_dataPtr->data(), data, size);
} else if (size > 0) {
Memset(m_dataPtr->data(), 0, size);
}
m_isImmutableStorage = true;
m_storageFlags = storageFlags;
m_change.DirtyRanges.clear();
m_change.DirtyRanges.Add({0, size});
m_change.Bits = BufferChangeBits::DirtyBit | BufferChangeBits::PreferReallocationBit;
++m_changeSerial;
}
void BufferObject::UploadData(DataPtr data, SizeT atOffset) { void BufferObject::UploadData(DataPtr data, SizeT atOffset) {
MOBILEGL_ASSERT(atOffset + data.size <= m_size, MOBILEGL_ASSERT(atOffset + data.size <= m_size,
"UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset, "UploadData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
data.size, m_size); data.size, m_size);
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
"Cannot upload data while buffer is non-persistently mapped.");
Memcpy(m_dataPtr->data() + atOffset, data.data, data.size); Memcpy(m_dataPtr->data() + atOffset, data.data, data.size);
m_change.DirtyRanges.Add({atOffset, atOffset + data.size}); m_change.DirtyRanges.Add({atOffset, atOffset + data.size});
m_change.Bits |= BufferChangeBits::DirtyBit; m_change.Bits |= BufferChangeBits::DirtyBit;
@@ -52,8 +74,10 @@ namespace MobileGL::MG_State::GLState {
if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer if (m_mappingAccess & BufferMappingAccessBit::Write) { // if we wrote to the buffer
if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly if (!(m_mappingAccess & BufferMappingAccessBit::FlushExplicit)) { // if we didn't flush explicitly
Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(), if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) {
m_mappedRange.end - m_mappedRange.start); Memcpy(m_dataPtr->data() + m_mappedRange.start, m_stagingData.data(),
m_mappedRange.end - m_mappedRange.start);
}
m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end}); m_change.DirtyRanges.Add({m_mappedRange.start, m_mappedRange.end});
m_change.Bits |= BufferChangeBits::DirtyBit; m_change.Bits |= BufferChangeBits::DirtyBit;
++m_changeSerial; ++m_changeSerial;
@@ -80,14 +104,29 @@ namespace MobileGL::MG_State::GLState {
MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)", MOBILEGL_ASSERT(end <= m_mappedRange.end, "Flush range out of bounds: mappedRange.end (%zu) < end (%zu)",
m_mappedRange.end, end); m_mappedRange.end, end);
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length); if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) {
Memcpy(m_dataPtr->data() + start, m_stagingData.data() + offset, length);
}
m_change.DirtyRanges.Add({start, end}); m_change.DirtyRanges.Add({start, end});
m_change.Bits |= BufferChangeBits::DirtyBit; m_change.Bits |= BufferChangeBits::DirtyBit;
++m_changeSerial; ++m_changeSerial;
} }
void BufferObject::MarkPersistentMappedRangeDirty() {
if (!m_isMapped) return;
if (!(m_mappingAccess & BufferMappingAccessBit::Persistent)) return;
if (!(m_mappingAccess & BufferMappingAccessBit::Write)) return;
if (m_mappingAccess & BufferMappingAccessBit::FlushExplicit) return;
if (m_mappedRange.start >= m_mappedRange.end) return;
m_change.DirtyRanges.Add(m_mappedRange);
m_change.Bits |= BufferChangeBits::DirtyBit;
++m_changeSerial;
}
void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) { void BufferObject::UploadSubData(DataPtr data, SizeT atOffset) {
MOBILEGL_ASSERT(!m_isMapped, "Cannot upload sub data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
"Cannot upload sub data while buffer is non-persistently mapped.");
MOBILEGL_ASSERT(atOffset + data.size <= m_size, MOBILEGL_ASSERT(atOffset + data.size <= m_size,
"UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset, "UploadSubData out of bounds: atOffset (%zu) + data.size (%zu) > m_size (%zu)", atOffset,
data.size, m_size); data.size, m_size);
@@ -101,8 +140,10 @@ namespace MobileGL::MG_State::GLState {
} }
void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size) { void BufferObject::CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size) {
MOBILEGL_ASSERT(!m_isMapped, "Cannot copy data while buffer is mapped."); MOBILEGL_ASSERT(!m_isMapped || (m_mappingAccess & BufferMappingAccessBit::Persistent),
MOBILEGL_ASSERT(!src->IsMapped(), "Cannot copy data from a buffer that is mapped."); "Cannot copy data while destination buffer is non-persistently mapped.");
MOBILEGL_ASSERT(!src->IsMapped() || (src->GetMappingAccess() & BufferMappingAccessBit::Persistent),
"Cannot copy data from a buffer that is non-persistently mapped.");
MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(), MOBILEGL_ASSERT(srcOffset + size <= src->GetSize(),
"Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)", "Source buffer copy out of bounds: srcOffset (%zu) + size (%zu) > src->GetSize() (%zu)",
srcOffset, size, src->GetSize()); srcOffset, size, src->GetSize());
@@ -159,6 +200,19 @@ namespace MobileGL::MG_State::GLState {
? BufferChangeBits::ForbidUnsynchronizationBit ? BufferChangeBits::ForbidUnsynchronizationBit
: BufferChangeBits::None; : BufferChangeBits::None;
m_change.Bits |=
!(access & BufferMappingAccessBit::InvalidateBuffer || access & BufferMappingAccessBit::InvalidateRange)
? BufferChangeBits::ForbidInvalidationBit
: BufferChangeBits::None;
m_change.Bits |= !(access & BufferMappingAccessBit::Unsynchronized)
? BufferChangeBits::ForbidUnsynchronizationBit
: BufferChangeBits::None;
if (access & BufferMappingAccessBit::Persistent) {
m_ownsStagingData = false;
return m_dataPtr->data() + range.start;
}
if (access & BufferMappingAccessBit::Write) { if (access & BufferMappingAccessBit::Write) {
m_stagingData.resize(range.end - range.start); m_stagingData.resize(range.end - range.start);
m_ownsStagingData = true; m_ownsStagingData = true;
@@ -187,6 +241,10 @@ namespace MobileGL::MG_State::GLState {
return m_size; return m_size;
} }
Bool BufferObject::IsImmutableStorage() const {
return m_isImmutableStorage;
}
BufferUsage BufferObject::GetUsage() const { BufferUsage BufferObject::GetUsage() const {
return m_usage; return m_usage;
} }
@@ -211,22 +269,25 @@ namespace MobileGL::MG_State::GLState {
return m_isMapped ? m_mappedRange : Range1D{0, 0}; return m_isMapped ? m_mappedRange : Range1D{0, 0};
} }
void* BufferObject::GetMappedPointer() { void* BufferObject::GetMappedPointer() const {
if (!m_isMapped) { if (!m_isMapped) return nullptr;
return nullptr; if (m_mappingAccess & BufferMappingAccessBit::Persistent) {
return const_cast<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
} }
if (m_ownsStagingData) { if (m_ownsStagingData) {
return m_stagingData.data(); return const_cast<Uint8*>(m_stagingData.data());
} }
return const_cast<Uint8*>(m_dataPtr->data()) + m_mappedRange.start;
return m_dataPtr->data() + m_mappedRange.start;
} }
Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const { Flags<BufferMappingAccessBit> BufferObject::GetMappingAccess() const {
return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null; return m_isMapped ? m_mappingAccess : BufferMappingAccessBit::Null;
} }
GLbitfield BufferObject::GetStorageFlags() const {
return m_storageFlags;
}
Uint BufferObject::GetExternalIndex() const { Uint BufferObject::GetExternalIndex() const {
return m_externalIndex; return m_externalIndex;
} }
@@ -25,6 +25,7 @@ namespace MobileGL {
AtomicCounter, AtomicCounter,
DispatchIndirect, DispatchIndirect,
DrawIndirect, DrawIndirect,
Parameter,
ShaderStorage, ShaderStorage,
BufferTargetCount, BufferTargetCount,
Unknown = -1 Unknown = -1
@@ -80,23 +81,27 @@ namespace MobileGL {
BufferObject(Uint externalIndex); BufferObject(Uint externalIndex);
void Resize(SizeT size); void Resize(SizeT size);
void AllocateImmutableStorage(SizeT size, const void* data, GLbitfield storageFlags);
void UploadData(DataPtr data, SizeT atOffset); void UploadData(DataPtr data, SizeT atOffset);
void SetUsage(BufferUsage usage); void SetUsage(BufferUsage usage);
void* AcquireMemory(Bool markMapped, Bool read, Bool write); void* AcquireMemory(Bool markMapped, Bool read, Bool write);
void* AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access); void* AcquireMemoryRange(Range1D range, Flags<BufferMappingAccessBit> access);
void ReleaseMemory(); void ReleaseMemory();
void FlushMemoryRange(SizeT offset, SizeT length); void FlushMemoryRange(SizeT offset, SizeT length);
void MarkPersistentMappedRangeDirty();
void UploadSubData(DataPtr data, SizeT atOffset); void UploadSubData(DataPtr data, SizeT atOffset);
void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size); void CopyDataFrom(const SharedPtr<BufferObject>& src, SizeT srcOffset, SizeT dstOffset, SizeT size);
void ClearDirty(); void ClearDirty();
Bool IsMapped() const; Bool IsMapped() const;
Bool IsImmutableStorage() const;
SizeT GetSize() const; SizeT GetSize() const;
BufferUsage GetUsage() const; BufferUsage GetUsage() const;
Range1D GetMappedRange() const; Range1D GetMappedRange() const;
void* GetMappedPointer(); void* GetMappedPointer() const;
const SharedPtr<Data>& GetDataReadOnly() const; const SharedPtr<Data>& GetDataReadOnly() const;
Flags<BufferMappingAccessBit> GetMappingAccess() const; Flags<BufferMappingAccessBit> GetMappingAccess() const;
GLbitfield GetStorageFlags() const;
Uint GetExternalIndex() const; Uint GetExternalIndex() const;
const VecRange1D& GetDirtyRanges() const; const VecRange1D& GetDirtyRanges() const;
Flags<BufferChangeBits> GetChangeBits() const; Flags<BufferChangeBits> GetChangeBits() const;
@@ -109,6 +114,8 @@ namespace MobileGL {
SharedPtr<Data> m_dataPtr; SharedPtr<Data> m_dataPtr;
Bool m_isMapped; Bool m_isMapped;
Flags<BufferMappingAccessBit> m_mappingAccess; Flags<BufferMappingAccessBit> m_mappingAccess;
Bool m_isImmutableStorage = false;
GLbitfield m_storageFlags = 0;
BufferChange m_change; BufferChange m_change;
Uint64 m_changeSerial = 0; Uint64 m_changeSerial = 0;
Range1D m_mappedRange; Range1D m_mappedRange;
@@ -16,7 +16,7 @@ namespace MobileGL::MG_State::GLState {
ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite, ToArray(BufferTarget::Vertex, BufferTarget::Uniform, BufferTarget::CopyRead, BufferTarget::CopyWrite,
BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture, BufferTarget::PixelPack, BufferTarget::PixelUnpack, BufferTarget::Query, BufferTarget::Texture,
BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect, BufferTarget::TransformFeedback, BufferTarget::AtomicCounter, BufferTarget::DispatchIndirect,
BufferTarget::DrawIndirect, BufferTarget::ShaderStorage); BufferTarget::DrawIndirect, BufferTarget::Parameter, BufferTarget::ShaderStorage);
constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback, constexpr const auto BufferBindPointTargets = ToArray(BufferTarget::Uniform, BufferTarget::TransformFeedback,
BufferTarget::AtomicCounter, BufferTarget::ShaderStorage); BufferTarget::AtomicCounter, BufferTarget::ShaderStorage);
+8
View File
@@ -502,6 +502,14 @@ namespace MobileGL::MG_State {
return m_renderState.GetFrontFaceMode(); return m_renderState.GetFrontFaceMode();
} }
void GLContext::SetProvokingVertexMode(ProvokingVertexMode mode) {
m_renderState.SetProvokingVertexMode(mode);
}
ProvokingVertexMode GLContext::GetProvokingVertexMode() const {
return m_renderState.GetProvokingVertexMode();
}
void GLContext::SetScissorBox(IntVec4 box) { void GLContext::SetScissorBox(IntVec4 box) {
m_renderState.SetScissorBox(box); m_renderState.SetScissorBox(box);
} }
+2
View File
@@ -159,6 +159,8 @@ namespace MobileGL {
CullFaceMode GetCullFaceMode() const; CullFaceMode GetCullFaceMode() const;
void SetFrontFaceMode(FrontFaceMode mode); void SetFrontFaceMode(FrontFaceMode mode);
FrontFaceMode GetFrontFaceMode() const; FrontFaceMode GetFrontFaceMode() const;
void SetProvokingVertexMode(ProvokingVertexMode mode);
ProvokingVertexMode GetProvokingVertexMode() const;
void SetScissorBox(IntVec4 box); // x, y, width, height void SetScissorBox(IntVec4 box); // x, y, width, height
const IntVec4& GetScissorBox() const; // x, y, width, height const IntVec4& GetScissorBox() const; // x, y, width, height
@@ -321,6 +321,27 @@ namespace MobileGL::MG_State::GLState {
} }
} }
for (int i = 0; i < m_activeUniformCount; i++) {
auto& uniform = m_program->getUniform(i);
const auto locationIt = m_uniformLocations.find(uniform.name);
if (locationIt == m_uniformLocations.end()) {
continue;
}
const Uint location = locationIt->second;
if (location >= m_uniformSamplerOrImageUnitIndex.size() || uniform.getType() == nullptr ||
!uniform.getType()->isOpaque() || (!uniform.getType()->isTexture() && !uniform.getType()->isImage())) {
continue;
}
const int binding = uniform.getBinding();
if (binding >= 0 && binding != static_cast<int>(glslang::TQualifier::layoutBindingEnd)) {
m_uniformSamplerOrImageUnitIndex[location] = binding;
MGLOG_D("ProgramObject %u: Reflection - opaque uniform '%s' location=%u initialUnit=%d",
m_externalIndex, uniform.name.c_str(), location, binding);
}
}
// ------------ attributes (vertex in) --------------- // ------------ attributes (vertex in) ---------------
Int inCount = m_program->getNumPipeInputs(); Int inCount = m_program->getNumPipeInputs();
MGLOG_D("ProgramObject %u: Reflection - pipe input count (attributes) = %d", m_externalIndex, inCount); MGLOG_D("ProgramObject %u: Reflection - pipe input count (attributes) = %d", m_externalIndex, inCount);
@@ -546,6 +546,17 @@ namespace MobileGL {
return m_parameters.FrontFaceModeSetting; return m_parameters.FrontFaceModeSetting;
} }
void RenderState::SetProvokingVertexMode(ProvokingVertexMode mode) {
if (m_parameters.ProvokingVertexModeSetting == mode) return;
m_parameters.ProvokingVertexModeSetting = mode;
++m_version;
}
ProvokingVertexMode RenderState::GetProvokingVertexMode() const {
return m_parameters.ProvokingVertexModeSetting;
}
// --------------------- Scissor --------------------- // --------------------- Scissor ---------------------
void RenderState::SetScissorBox(IntVec4 box) { void RenderState::SetScissorBox(IntVec4 box) {
if (m_parameters.ScissorBox == box) return; if (m_parameters.ScissorBox == box) return;
@@ -135,6 +135,13 @@ namespace MobileGL {
Unknown = -1 Unknown = -1
}; };
enum class ProvokingVertexMode {
FirstVertex,
LastVertex,
ProvokingVertexModeCount,
Unknown = -1
};
enum class CapabilityInput { enum class CapabilityInput {
Blend, Blend,
ClipDistance0, ClipDistance0,
@@ -241,6 +248,7 @@ namespace MobileGL {
Bool CullFaceEnabled = false; Bool CullFaceEnabled = false;
CullFaceMode CullFaceModeSetting = CullFaceMode::Back; CullFaceMode CullFaceModeSetting = CullFaceMode::Back;
FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise; FrontFaceMode FrontFaceModeSetting = FrontFaceMode::CounterClockwise;
ProvokingVertexMode ProvokingVertexModeSetting = ProvokingVertexMode::LastVertex;
// Scissor // Scissor
Bool ColorLogicOpEnabled = false; Bool ColorLogicOpEnabled = false;
@@ -349,6 +357,8 @@ namespace MobileGL {
CullFaceMode GetCullFaceMode() const; CullFaceMode GetCullFaceMode() const;
void SetFrontFaceMode(FrontFaceMode mode); void SetFrontFaceMode(FrontFaceMode mode);
FrontFaceMode GetFrontFaceMode() const; FrontFaceMode GetFrontFaceMode() const;
void SetProvokingVertexMode(ProvokingVertexMode mode);
ProvokingVertexMode GetProvokingVertexMode() const;
// Scissor // Scissor
void SetScissorBox(IntVec4 box); // x, y, width, height void SetScissorBox(IntVec4 box); // x, y, width, height
+272
View File
@@ -330,6 +330,127 @@ TEST_F(BufferTest, DeleteBufferObject) {
ASSERT_FALSE(MobileGL::MG_State::pGLContext->GetBufferObject(bufferNames[0])); ASSERT_FALSE(MobileGL::MG_State::pGLContext->GetBufferObject(bufferNames[0]));
} }
TEST_F(BufferTest, ParameterBufferBindingAndQuery) {
Vector<Uint> bufferNames;
MobileGL::MG_State::pGLContext->GenBufferNames(1, bufferNames);
auto bufObj = MobileGL::MG_State::pGLContext->CreateBufferObject(bufferNames[0]);
auto& slot = MobileGL::MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::Parameter);
slot.Bind(bufObj);
GLint binding = 0;
MobileGL::MG_Impl::GLImpl::GetIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, &binding);
EXPECT_EQ(binding, static_cast<GLint>(bufferNames[0]));
slot.Bind(nullptr);
MobileGL::MG_Impl::GLImpl::GetIntegerv(GL_PARAMETER_BUFFER_BINDING_ARB, &binding);
EXPECT_EQ(binding, 0);
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, BindBufferBaseZeroUnbindsBindingPoint) {
GLuint buffer = 0;
MobileGL::MG_Impl::GLImpl::GenBuffers(1, &buffer);
MobileGL::MG_Impl::GLImpl::BindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
MobileGL::MG_Impl::GLImpl::BufferData(GL_SHADER_STORAGE_BUFFER, 16, nullptr, GL_DYNAMIC_DRAW);
MobileGL::MG_Impl::GLImpl::BindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, buffer);
auto& point = MobileGL::MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, 2);
ASSERT_NE(point.GetBoundObject(), nullptr);
EXPECT_EQ(point.GetBoundObject()->GetExternalIndex(), buffer);
MobileGL::MG_Impl::GLImpl::BindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, 0);
EXPECT_EQ(point.GetBoundObject(), nullptr);
EXPECT_FALSE(MobileGL::MG_State::pGLContext->ValidateBufferObject(0));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, BindBufferRangeZeroUnbindsBindingPoint) {
GLuint buffer = 0;
MobileGL::MG_Impl::GLImpl::GenBuffers(1, &buffer);
MobileGL::MG_Impl::GLImpl::BindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
MobileGL::MG_Impl::GLImpl::BufferData(GL_SHADER_STORAGE_BUFFER, 16, nullptr, GL_DYNAMIC_DRAW);
MobileGL::MG_Impl::GLImpl::BindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, buffer, 4, 8);
auto& point = MobileGL::MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, 3);
ASSERT_NE(point.GetBoundObject(), nullptr);
EXPECT_EQ(point.GetRange().start, 4);
EXPECT_EQ(point.GetRange().end, 12);
MobileGL::MG_Impl::GLImpl::BindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, 0, 0, 0);
EXPECT_EQ(point.GetBoundObject(), nullptr);
EXPECT_FALSE(MobileGL::MG_State::pGLContext->ValidateBufferObject(0));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, GetInteger64vMaxShaderStorageBlockSize) {
GLint64 maxSsboBlockSize = 0;
MobileGL::MG_Impl::GLImpl::GetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxSsboBlockSize);
EXPECT_GT(maxSsboBlockSize, 0);
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, CreateBuffersCreatesObjectsImmediately) {
GLuint buffers[2] = {};
MobileGL::MG_Impl::GLImpl::CreateBuffers(2, buffers);
EXPECT_NE(buffers[0], 0u);
EXPECT_NE(buffers[1], 0u);
EXPECT_TRUE(MobileGL::MG_State::pGLContext->ValidateBufferObject(buffers[0]));
EXPECT_TRUE(MobileGL::MG_State::pGLContext->ValidateBufferObject(buffers[1]));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, CopyNamedBufferSubDataCopiesBetweenDSABuffers) {
GLuint buffers[2] = {};
MobileGL::MG_Impl::GLImpl::CreateBuffers(2, buffers);
Vector<Uint8> src{1, 2, 3, 4, 5, 6};
Vector<Uint8> dst(src.size(), 0);
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffers[0], src.size(), src.data(), GL_STATIC_DRAW);
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffers[1], dst.size(), dst.data(), GL_STATIC_DRAW);
MobileGL::MG_Impl::GLImpl::CopyNamedBufferSubData(buffers[0], buffers[1], 1, 2, 3);
Vector<Uint8> actual(dst.size());
auto dstObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffers[1]);
Memcpy(actual.data(), dstObject->AcquireMemory(false, true, false), actual.size());
EXPECT_EQ(actual, (Vector<Uint8>{0, 0, 2, 3, 4, 0}));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, ClearNamedBufferDataZeroesStorage) {
GLuint buffer = 0;
MobileGL::MG_Impl::GLImpl::CreateBuffers(1, &buffer);
Vector<Uint8> initial(8, 0x7F);
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffer, initial.size(), initial.data(), GL_STATIC_DRAW);
MobileGL::MG_Impl::GLImpl::ClearNamedBufferData(buffer, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr);
Vector<Uint8> actual(initial.size(), 0xFF);
auto bufferObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffer);
Memcpy(actual.data(), bufferObject->AcquireMemory(false, true, false), actual.size());
EXPECT_EQ(actual, Vector<Uint8>(initial.size(), 0));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(BufferTest, ClearNamedBufferSubDataRepeatsPattern) {
GLuint buffer = 0;
MobileGL::MG_Impl::GLImpl::CreateBuffers(1, &buffer);
Vector<Uint32> initial{0, 0, 0, 0, 0};
MobileGL::MG_Impl::GLImpl::NamedBufferData(buffer, initial.size() * sizeof(Uint32), initial.data(), GL_STATIC_DRAW);
const Uint32 pattern = 0xAABBCCDDu;
MobileGL::MG_Impl::GLImpl::ClearNamedBufferSubData(buffer, GL_R32UI, sizeof(Uint32), sizeof(Uint32) * 3,
GL_RED_INTEGER, GL_UNSIGNED_INT, &pattern);
Vector<Uint32> actual(initial.size(), 0);
auto bufferObject = MobileGL::MG_State::pGLContext->GetBufferObject(buffer);
Memcpy(actual.data(), bufferObject->AcquireMemory(false, true, false), actual.size() * sizeof(Uint32));
EXPECT_EQ(actual, (Vector<Uint32>{0, pattern, pattern, pattern, 0}));
EXPECT_EQ(MobileGL::MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
using namespace MobileGL::MG_Impl::GLImpl; using namespace MobileGL::MG_Impl::GLImpl;
class GeneralBufferTest : public ::testing::Test { class GeneralBufferTest : public ::testing::Test {
@@ -477,6 +598,157 @@ TEST_F(GeneralBufferTest, General_MapFlags) {
EXPECT_EQ(GetError(), GL_NO_ERROR); EXPECT_EQ(GetError(), GL_NO_ERROR);
} }
TEST_F(GeneralBufferTest, General_BufferStorageQueriesImmutable) {
GLuint buffer = 0;
GenBuffers(1, &buffer);
BindBuffer(GL_ARRAY_BUFFER, buffer);
const GLint initial[] = {1, 2, 3, 4};
constexpr GLbitfield storageFlags = GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT;
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, storageFlags);
EXPECT_EQ(GetError(), GL_NO_ERROR);
GLint immutable = GL_FALSE;
GLint reportedFlags = 0;
GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &immutable);
GetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_STORAGE_FLAGS, &reportedFlags);
EXPECT_EQ(immutable, GL_TRUE);
EXPECT_EQ(reportedFlags, static_cast<GLint>(storageFlags));
const GLint update = 42;
BufferSubData(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(update), &update);
EXPECT_EQ(GetError(), GL_NO_ERROR);
BufferData(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_DYNAMIC_DRAW);
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
}
TEST_F(GeneralBufferTest, General_PersistentMapRequiresStorageFlags) {
GLuint mutableBuffer = CreateBoundBuffer(GL_ARRAY_BUFFER, 64, GL_DYNAMIC_DRAW);
(void)mutableBuffer;
void* mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
EXPECT_EQ(mapped, nullptr);
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
GLuint storageBuffer = 0;
GenBuffers(1, &storageBuffer);
BindBuffer(GL_ARRAY_BUFFER, storageBuffer);
BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT);
EXPECT_EQ(GetError(), GL_NO_ERROR);
mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
EXPECT_EQ(mapped, nullptr);
EXPECT_EQ(GetError(), GL_INVALID_OPERATION);
GLuint persistentBuffer = 0;
GenBuffers(1, &persistentBuffer);
BindBuffer(GL_ARRAY_BUFFER, persistentBuffer);
BufferStorage(GL_ARRAY_BUFFER, 64, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT);
EXPECT_EQ(GetError(), GL_NO_ERROR);
mapped = MapBufferRange(GL_ARRAY_BUFFER, 0, 16, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
ASSERT_NE(mapped, nullptr);
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralBufferTest, General_PersistentCoherentWriteDirtyWithoutUnmap) {
GLuint buffer = 0;
GenBuffers(1, &buffer);
BindBuffer(GL_ARRAY_BUFFER, buffer);
GLint initial[] = {10, 20, 30, 40};
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial,
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
EXPECT_EQ(GetError(), GL_NO_ERROR);
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
ASSERT_NE(bufferObject, nullptr);
bufferObject->ClearDirty();
auto* mapped = static_cast<GLint*>(
MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial),
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT));
ASSERT_NE(mapped, nullptr);
mapped[2] = 1234;
bufferObject->MarkPersistentMappedRangeDirty();
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0);
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(initial));
const auto data = bufferObject->GetDataReadOnly();
EXPECT_EQ(reinterpret_cast<const GLint*>(data->data())[2], 1234);
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralBufferTest, General_PersistentExplicitFlushOnlyDirtiesFlushedRange) {
GLuint buffer = 0;
GenBuffers(1, &buffer);
BindBuffer(GL_ARRAY_BUFFER, buffer);
GLint initial[] = {10, 20, 30, 40};
BufferStorage(GL_ARRAY_BUFFER, sizeof(initial), initial, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
EXPECT_EQ(GetError(), GL_NO_ERROR);
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
ASSERT_NE(bufferObject, nullptr);
bufferObject->ClearDirty();
auto* mapped = static_cast<GLint*>(
MapBufferRange(GL_ARRAY_BUFFER, 0, sizeof(initial),
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
ASSERT_NE(mapped, nullptr);
mapped[1] = 200;
mapped[3] = 400;
bufferObject->MarkPersistentMappedRangeDirty();
EXPECT_TRUE(bufferObject->GetDirtyRanges().empty());
FlushMappedBufferRange(GL_ARRAY_BUFFER, sizeof(GLint), sizeof(GLint));
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, sizeof(GLint));
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint) * 2);
EXPECT_TRUE(UnmapBuffer(GL_ARRAY_BUFFER));
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralBufferTest, General_NamedBufferStorageMappingWrappers) {
GLuint buffer = 0;
GenBuffers(1, &buffer);
GLint initial[] = {1, 2, 3, 4};
NamedBufferStorage(buffer, sizeof(initial), initial,
GL_DYNAMIC_STORAGE_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
EXPECT_EQ(GetError(), GL_NO_ERROR);
GLint immutable = GL_FALSE;
GetNamedBufferParameteriv(buffer, GL_BUFFER_IMMUTABLE_STORAGE, &immutable);
EXPECT_EQ(immutable, GL_TRUE);
auto bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
ASSERT_NE(bufferObject, nullptr);
bufferObject->ClearDirty();
auto* mapped = static_cast<GLint*>(
MapNamedBufferRange(buffer, 0, sizeof(initial),
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
ASSERT_NE(mapped, nullptr);
mapped[0] = 99;
void* mapPointer = nullptr;
GetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &mapPointer);
EXPECT_EQ(mapPointer, mapped);
FlushMappedNamedBufferRange(buffer, 0, sizeof(GLint));
ASSERT_FALSE(bufferObject->GetDirtyRanges().empty());
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].start, 0);
EXPECT_EQ(bufferObject->GetDirtyRanges()[0].end, sizeof(GLint));
EXPECT_TRUE(UnmapNamedBuffer(buffer));
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralBufferTest, General_GeneralTest_1) { TEST_F(GeneralBufferTest, General_GeneralTest_1) {
GLuint buffers[3]; GLuint buffers[3];
GenBuffers(3, buffers); GenBuffers(3, buffers);
+7
View File
@@ -8,6 +8,9 @@ add_executable(
target_include_directories(BufferTest PRIVATE target_include_directories(BufferTest PRIVATE
${MGL_ROOT}/include ${MGL_ROOT}/include
${MGL_ROOT}/MobileGL ${MGL_ROOT}/MobileGL
${MGL_ROOT}/3rdparty/xxHash
${MGL_ROOT}/3rdparty/Vulkan-Headers/include
${MGL_ROOT}/3rdparty/SPIRV-Reflect
) )
target_link_libraries( target_link_libraries(
@@ -16,5 +19,9 @@ target_link_libraries(
${LINK_LIBRARIES} ${LINK_LIBRARIES}
) )
if (MSVC)
target_compile_options(BufferTest PRIVATE /Zc:preprocessor)
endif()
include(GoogleTest) include(GoogleTest)
gtest_discover_tests(BufferTest) gtest_discover_tests(BufferTest)
+2
View File
@@ -65,6 +65,8 @@ include(GoogleTest)
gtest_discover_tests(SanityTest) gtest_discover_tests(SanityTest)
add_subdirectory(Buffer) add_subdirectory(Buffer)
add_subdirectory(Framebuffer)
add_subdirectory(Texture)
add_subdirectory(VertexArray) add_subdirectory(VertexArray)
add_subdirectory(Program) add_subdirectory(Program)
if (ENABLE_INTEGRATION_TESTS) if (ENABLE_INTEGRATION_TESTS)
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.14)
add_executable(
FramebufferTest
FramebufferTest.cpp
)
target_include_directories(FramebufferTest PRIVATE
${MGL_ROOT}/include
${MGL_ROOT}/MobileGL
)
target_link_libraries(
FramebufferTest PRIVATE
GTest::gtest_main
${LINK_LIBRARIES}
)
include(GoogleTest)
gtest_discover_tests(FramebufferTest)
@@ -0,0 +1,333 @@
// MobileGL - MobileGL/MG_Test/Framebuffer/FramebufferTest.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include <gtest/gtest.h>
#include "Includes.h"
#include "Init.h"
#include <MG_Backend/BackendObjects.h>
#include <MG_Impl/GLImpl/Buffer/GL_Buffer.h>
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
#include <MG_State/GLState/Core.h>
using namespace MobileGL;
namespace {
SharedPtr<MG_State::GLState::FramebufferObject> g_lastBlitReadFramebuffer;
SharedPtr<MG_State::GLState::FramebufferObject> g_lastBlitDrawFramebuffer;
Int g_blitNamedFramebufferCallCount = 0;
SharedPtr<MG_State::GLState::FramebufferObject> g_lastClearFramebuffer;
GLenum g_lastClearBuffer = GL_NONE;
GLint g_lastClearDrawbuffer = -1;
GLfloat g_lastClearDepth = -1.0f;
GLint g_lastClearStencil = -1;
FloatVec4 g_lastClearColor = {};
Int g_clearNamedFramebufferfvCallCount = 0;
Int g_clearNamedFramebufferfiCallCount = 0;
Int g_readPixelsCallCount = 0;
void RecordBlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
const SharedPtr<MG_State::GLState::FramebufferObject>& drawFramebuffer,
GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum) {
g_lastBlitReadFramebuffer = readFramebuffer;
g_lastBlitDrawFramebuffer = drawFramebuffer;
++g_blitNamedFramebufferCallCount;
}
void RecordClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value) {
g_lastClearFramebuffer = framebuffer;
g_lastClearBuffer = buffer;
g_lastClearDrawbuffer = drawbuffer;
if (value) {
if (buffer == GL_COLOR) {
g_lastClearColor = FloatVec4(value[0], value[1], value[2], value[3]);
} else if (buffer == GL_DEPTH) {
g_lastClearDepth = value[0];
}
}
++g_clearNamedFramebufferfvCallCount;
}
void RecordClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) {
g_lastClearFramebuffer = framebuffer;
g_lastClearBuffer = buffer;
g_lastClearDrawbuffer = drawbuffer;
g_lastClearDepth = depth;
g_lastClearStencil = stencil;
++g_clearNamedFramebufferfiCallCount;
}
void RecordReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*) {
++g_readPixelsCallCount;
}
} // namespace
class FramebufferTest : public ::testing::Test {
protected:
void SetUp() override {
MobileGL::Initialize();
g_lastBlitReadFramebuffer = nullptr;
g_lastBlitDrawFramebuffer = nullptr;
g_blitNamedFramebufferCallCount = 0;
g_lastClearFramebuffer = nullptr;
g_lastClearBuffer = GL_NONE;
g_lastClearDrawbuffer = -1;
g_lastClearDepth = -1.0f;
g_lastClearStencil = -1;
g_lastClearColor = {};
g_clearNamedFramebufferfvCallCount = 0;
g_clearNamedFramebufferfiCallCount = 0;
g_readPixelsCallCount = 0;
MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer = nullptr;
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv = nullptr;
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi = nullptr;
MG_Backend::gBackendFunctionsTable.GL.ReadPixels = nullptr;
}
};
TEST_F(FramebufferTest, CreateFramebuffersCreatesObjectsImmediately) {
GLuint framebuffers[2] = {};
MG_Impl::GLImpl::CreateFramebuffers(2, framebuffers);
EXPECT_NE(framebuffers[0], 0u);
EXPECT_NE(framebuffers[1], 0u);
EXPECT_TRUE(MG_State::pGLContext->ValidateFramebufferObject(framebuffers[0]));
EXPECT_TRUE(MG_State::pGLContext->ValidateFramebufferObject(framebuffers[1]));
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, NamedFramebufferTextureAttachesWithoutChangingBindings) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
Vector<Uint> textureNames;
MG_State::pGLContext->GenTextureNames(1, textureNames);
MG_State::pGLContext->CreateTextureObject(textureNames[0], TextureTarget::Texture2D);
const auto originalDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto originalRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, textureNames[0], 3);
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
const auto& attachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0);
EXPECT_TRUE(attachment.IsTexture());
EXPECT_EQ(attachment.GetTexture()->GetExternalIndex(), textureNames[0]);
EXPECT_EQ(attachment.GetTextureLevel(), 3);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, NamedDepthFramebufferTextureStorageIsCompleteWithoutBinding) {
GLuint framebuffer = 0;
GLuint texture = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
const auto originalDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto originalRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_DEPTH_COMPONENT24, 64, 32);
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_DEPTH_ATTACHMENT, texture, 0);
EXPECT_EQ(MG_Impl::GLImpl::CheckNamedFramebufferStatus(framebuffer, GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, ReadPixelsAllowsPersistentMappedPixelPackBuffer) {
GLuint framebuffer = 0;
GLuint texture = 0;
GLuint pixelPackBuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
MG_Impl::GLImpl::CreateBuffers(1, &pixelPackBuffer);
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 4, 4);
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, texture, 0);
MG_Impl::GLImpl::BindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
MG_Impl::GLImpl::BindBuffer(GL_PIXEL_PACK_BUFFER, pixelPackBuffer);
MG_Impl::GLImpl::BufferStorage(GL_PIXEL_PACK_BUFFER, 4 * 4 * 4, nullptr,
GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT);
ASSERT_NE(MG_Impl::GLImpl::MapBufferRange(GL_PIXEL_PACK_BUFFER, 0, 4 * 4 * 4,
GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT),
nullptr);
MG_Backend::gBackendFunctionsTable.GL.ReadPixels = RecordReadPixels;
MG_Impl::GLImpl::ReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
EXPECT_EQ(g_readPixelsCallCount, 1);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, NamedRenderbufferStorageAndFramebufferAttachDoNotChangeBindings) {
GLuint framebuffer = 0;
GLuint renderbuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
MG_Impl::GLImpl::CreateRenderbuffers(1, &renderbuffer);
const auto originalDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto originalRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
const auto originalRenderbuffer =
MG_State::pGLContext->GetRenderbufferBindingSlot(RenderbufferTarget::Renderbuffer).GetBoundObject();
MG_Impl::GLImpl::NamedRenderbufferStorage(renderbuffer, GL_RGBA8, 64, 32);
GLint width = 0;
GLint height = 0;
GLint format = 0;
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_WIDTH, &width);
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_HEIGHT, &height);
MG_Impl::GLImpl::GetNamedRenderbufferParameteriv(renderbuffer, GL_RENDERBUFFER_INTERNAL_FORMAT, &format);
EXPECT_EQ(width, 64);
EXPECT_EQ(height, 32);
EXPECT_EQ(format, GL_RGBA8);
MG_Impl::GLImpl::NamedFramebufferRenderbuffer(framebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
const auto& attachment = framebufferObject->GetAttachment(FramebufferAttachmentType::Color0);
EXPECT_TRUE(attachment.IsRenderbuffer());
EXPECT_EQ(attachment.GetRenderbuffer()->GetExternalIndex(), renderbuffer);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), originalDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), originalRead);
EXPECT_EQ(MG_State::pGLContext->GetRenderbufferBindingSlot(RenderbufferTarget::Renderbuffer).GetBoundObject(),
originalRenderbuffer);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, NamedFramebufferDrawBuffersDoNotModifyDefaultFramebuffer) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
const auto defaultDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto defaultRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
MG_Impl::GLImpl::NamedFramebufferDrawBuffers(framebuffer, 2, bufs);
MG_Impl::GLImpl::NamedFramebufferReadBuffer(framebuffer, GL_COLOR_ATTACHMENT1);
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
EXPECT_EQ(framebufferObject->GetDrawBuffers()[0], FramebufferAttachmentType::Color0);
EXPECT_EQ(framebufferObject->GetDrawBuffers()[1], FramebufferAttachmentType::Color1);
EXPECT_EQ(framebufferObject->GetReadBuffer(), FramebufferAttachmentType::Color1);
EXPECT_EQ(defaultDraw->GetDrawBuffers()[0], FramebufferAttachmentType::Color0);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, ClearNamedFramebufferfvUsesNamedObjectWithoutChangingBindings) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
const auto defaultDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto defaultRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
const GLfloat depth[] = {0.25f};
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfv = RecordClearNamedFramebufferfv;
MG_Impl::GLImpl::ClearNamedFramebufferfv(framebuffer, GL_DEPTH, 0, depth);
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
EXPECT_EQ(g_clearNamedFramebufferfvCallCount, 1);
EXPECT_EQ(g_lastClearFramebuffer, framebufferObject);
EXPECT_EQ(g_lastClearBuffer, GL_DEPTH);
EXPECT_EQ(g_lastClearDrawbuffer, 0);
EXPECT_EQ(g_lastClearDepth, 0.25f);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, ClearNamedFramebufferfiAllowsDefaultFramebufferZero) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
const auto defaultDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto defaultRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferfi = RecordClearNamedFramebufferfi;
MG_Impl::GLImpl::ClearNamedFramebufferfi(0, GL_DEPTH_STENCIL, 0, 0.5f, 7);
EXPECT_EQ(g_clearNamedFramebufferfiCallCount, 1);
EXPECT_EQ(g_lastClearFramebuffer, defaultDraw);
EXPECT_EQ(g_lastClearBuffer, GL_DEPTH_STENCIL);
EXPECT_EQ(g_lastClearDrawbuffer, 0);
EXPECT_EQ(g_lastClearDepth, 0.5f);
EXPECT_EQ(g_lastClearStencil, 7);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, GetNamedFramebufferAttachmentParameterivReadsTargetObjectDirectly) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
Vector<Uint> textureNames;
MG_State::pGLContext->GenTextureNames(1, textureNames);
MG_State::pGLContext->CreateTextureObject(textureNames[0], TextureTarget::Texture2D);
MG_Impl::GLImpl::NamedFramebufferTexture(framebuffer, GL_COLOR_ATTACHMENT0, textureNames[0], 2);
GLint objectType = 0;
GLint objectName = 0;
GLint textureLevel = 0;
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &objectType);
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &objectName);
MG_Impl::GLImpl::GetNamedFramebufferAttachmentParameteriv(
framebuffer, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &textureLevel);
EXPECT_EQ(objectType, GL_TEXTURE);
EXPECT_EQ(objectName, static_cast<GLint>(textureNames[0]));
EXPECT_EQ(textureLevel, 2);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(FramebufferTest, BlitNamedFramebufferAllowsDefaultFramebufferZero) {
GLuint framebuffer = 0;
MG_Impl::GLImpl::CreateFramebuffers(1, &framebuffer);
const auto defaultDraw =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
const auto defaultRead =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
MG_Backend::gBackendFunctionsTable.GL.BlitNamedFramebuffer = RecordBlitNamedFramebuffer;
MG_Impl::GLImpl::BlitNamedFramebuffer(framebuffer, 0, 0, 0, 16, 16, 0, 0, 16, 16, GL_COLOR_BUFFER_BIT,
GL_NEAREST);
const auto framebufferObject = MG_State::pGLContext->GetFramebufferObject(framebuffer);
EXPECT_EQ(g_blitNamedFramebufferCallCount, 1);
EXPECT_EQ(g_lastBlitReadFramebuffer, framebufferObject);
EXPECT_EQ(g_lastBlitDrawFramebuffer, defaultDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(), defaultDraw);
EXPECT_EQ(MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(), defaultRead);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
+208
View File
@@ -12,6 +12,10 @@
#include "Includes.h" #include "Includes.h"
#include "Init.h" #include "Init.h"
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
#include "MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h"
#include "MG_Backend/BackendObjects.h"
#include "MG_Impl/GLImpl/Getter/GL_Getter.h"
#include "MG_Impl/GLImpl/Program/GL_Program.h" #include "MG_Impl/GLImpl/Program/GL_Program.h"
#include "MG_State/GLState/Core.h" #include "MG_State/GLState/Core.h"
#include "MG_Util/ShaderTranspiler/ShaderCompiler.h" #include "MG_Util/ShaderTranspiler/ShaderCompiler.h"
@@ -116,6 +120,80 @@ TEST_F(ProgramTest, CompileFragment) {
CompileShader(fs); CompileShader(fs);
} }
TEST_F(ProgramTest, CompileVoxySubgroupProbeShader) {
char infoLog[1024] = "";
const char* csSrc = R"(#version 430
#extension GL_KHR_shader_subgroup_basic : require
#extension GL_KHR_shader_subgroup_arithmetic : require
layout(local_size_x=32) in;
void main() {
uint a = subgroupExclusiveAdd(gl_LocalInvocationIndex);
}
)";
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
ShaderSource(cs, 1, &csSrc, nullptr);
CompileShader(cs);
GLint compileStatus = GL_FALSE;
GetShaderiv(cs, GL_COMPILE_STATUS, &compileStatus);
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
EXPECT_EQ(compileStatus, GL_TRUE) << infoLog;
}
TEST_F(ProgramTest, CompileVoxyGpuShaderInt64QuadDecode) {
auto previousBackend = Move(MG_Backend::pActiveBackendObject);
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectVulkan::BackendObject_DirectVulkan>();
char infoLog[2048] = "";
const char* vsSrc = R"(#version 460 core
#extension GL_ARB_gpu_shader_int64 : enable
#ifdef GL_ARB_gpu_shader_int64
#define Quad uint64_t
#define Eu32(data, amountBits, shift) (uint((data)>>(shift))&((1u<<(amountBits))-1))
vec3 extractPos(uint64_t quad) {
return vec3(Eu32(quad, 5, 21), Eu32(quad, 5, 16), Eu32(quad, 5, 11));
}
uint extractStateId(uint64_t quad) {
return Eu32(quad, 16, 26);
}
uint extractBiomeId(uint64_t quad) {
return Eu32(quad, 9, 46);
}
#else
#error GL_ARB_gpu_shader_int64 should select Voxy native quad decode path
#endif
layout(std430, binding = 1) readonly buffer QuadBuffer {
Quad quadData[];
};
layout(location = 0) flat out uvec4 interData;
void main() {
uint64_t quad = quadData[uint(gl_VertexID) >> 2];
vec3 pos = extractPos(quad);
interData = uvec4(extractStateId(quad), extractBiomeId(quad), uint(pos.x), uint(pos.y));
gl_Position = vec4(pos * (1.0 / 32.0), 1.0);
}
)";
GLuint vs = CreateShader(GL_VERTEX_SHADER);
ShaderSource(vs, 1, &vsSrc, nullptr);
CompileShader(vs);
GLint compileStatus = GL_FALSE;
GetShaderiv(vs, GL_COMPILE_STATUS, &compileStatus);
GetShaderInfoLog(vs, sizeof(infoLog), nullptr, infoLog);
EXPECT_EQ(compileStatus, GL_TRUE) << infoLog;
MG_Backend::pActiveBackendObject = Move(previousBackend);
}
TEST_F(ProgramTest, ShaderSourceKeepsOriginalTextAfterCompile) { TEST_F(ProgramTest, ShaderSourceKeepsOriginalTextAfterCompile) {
const char* part0 = R"(#define HIGHP_OR_DEFAULT highp const char* part0 = R"(#define HIGHP_OR_DEFAULT highp
attribute vec4 Position; attribute vec4 Position;
@@ -203,6 +281,79 @@ void main() {
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog; ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
} }
TEST_F(ProgramTest, ImageUniformLayoutBindingInitializesImageUnit) {
char infoLog[1024] = "";
const char* csSrc = R"(#version 460 core
layout(local_size_x = 1) in;
layout(binding = 4, rgba8) uniform writeonly image2D colourTexOut;
void main() {
imageStore(colourTexOut, ivec2(0), vec4(1.0));
}
)";
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
ShaderSource(cs, 1, &csSrc, nullptr);
CompileShader(cs);
GLint csStatus = GL_FALSE;
GetShaderiv(cs, GL_COMPILE_STATUS, &csStatus);
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
ASSERT_EQ(csStatus, GL_TRUE) << infoLog;
GLuint program = CreateProgram();
AttachShader(program, cs);
LinkProgram(program);
GLint linkStatus = GL_FALSE;
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
GetProgramInfoLog(program, sizeof(infoLog), nullptr, infoLog);
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
const GLint location = GetUniformLocation(program, "colourTexOut");
ASSERT_GE(location, 0);
auto programObject = MobileGL::MG_State::pGLContext->GetProgramObject(program);
ASSERT_NE(programObject, nullptr);
EXPECT_EQ(programObject->GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location)), 4);
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(ProgramTest, DirectVulkanStorageBlockUsesShaderLayoutBinding) {
char infoLog[1024] = "";
const char* csSrc = R"(#version 460 core
layout(local_size_x = 1) in;
layout(std430, binding = 2) buffer requestQueueStruct {
uint value;
} requestQueue;
void main() {
requestQueue.value = 1u;
}
)";
GLuint cs = CreateShader(GL_COMPUTE_SHADER);
ShaderSource(cs, 1, &csSrc, nullptr);
CompileShader(cs);
GLint csStatus = GL_FALSE;
GetShaderiv(cs, GL_COMPILE_STATUS, &csStatus);
GetShaderInfoLog(cs, sizeof(infoLog), nullptr, infoLog);
ASSERT_EQ(csStatus, GL_TRUE) << infoLog;
GLuint program = CreateProgram();
AttachShader(program, cs);
LinkProgram(program);
GLint linkStatus = GL_FALSE;
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
GetProgramInfoLog(program, sizeof(infoLog), nullptr, infoLog);
ASSERT_EQ(linkStatus, GL_TRUE) << infoLog;
auto programObject = MobileGL::MG_State::pGLContext->GetProgramObject(program);
ASSERT_NE(programObject, nullptr);
const GLuint blockIndex =
MG_Backend::DirectVulkan::GetShaderStorageBlockIndex(*programObject, "requestQueueStruct");
ASSERT_NE(blockIndex, GL_INVALID_INDEX);
EXPECT_EQ(MG_Backend::DirectVulkan::GetShaderStorageBlockBinding(*programObject, blockIndex), 2u);
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(ProgramTest, CompileAndLink) { TEST_F(ProgramTest, CompileAndLink) {
char infoLog[1024] = ""; char infoLog[1024] = "";
@@ -306,6 +457,63 @@ TEST_F(ProgramTest, CompileAndLink) {
} }
} }
TEST_F(ProgramTest, Uniform1uiStoresUnsignedValue) {
char infoLog[1024] = "";
const char* simpleVs = R"(#version 460
layout(location = 0) in vec4 Position;
void main() {
gl_Position = Position;
}
)";
const char* uintFs = R"(#version 460
uniform uint NodeQueueIndex;
out vec4 fragColor;
void main() {
fragColor = vec4(float(NodeQueueIndex & 255u));
}
)";
GLuint vs = CreateShader(GL_VERTEX_SHADER);
ShaderSource(vs, 1, &simpleVs, NULL);
CompileShader(vs);
GLint vsStatus = GL_FALSE;
GetShaderiv(vs, GL_COMPILE_STATUS, &vsStatus);
GetShaderInfoLog(vs, 1024, nullptr, infoLog);
ASSERT_EQ(vsStatus, GL_TRUE) << infoLog;
GLuint fs = CreateShader(GL_FRAGMENT_SHADER);
ShaderSource(fs, 1, &uintFs, NULL);
CompileShader(fs);
GLint fsStatus = GL_FALSE;
GetShaderiv(fs, GL_COMPILE_STATUS, &fsStatus);
GetShaderInfoLog(fs, 1024, nullptr, infoLog);
ASSERT_EQ(fsStatus, GL_TRUE) << infoLog;
GLuint program = CreateProgram();
AttachShader(program, vs);
AttachShader(program, fs);
LinkProgram(program);
GLint linkStatus = GL_FALSE;
GetProgramiv(program, GL_LINK_STATUS, &linkStatus);
ASSERT_EQ(linkStatus, GL_TRUE);
UseProgram(program);
GLint loc = GetUniformLocation(program, "NodeQueueIndex");
ASSERT_GE(loc, 0);
const GLuint expected = 0xF1234567u;
Uniform1ui(loc, expected);
GLint actual = 0;
GetUniformiv(program, loc, &actual);
EXPECT_EQ(static_cast<GLuint>(actual), expected);
}
TEST_F(ProgramTest, UniformMatrixFunctions) { TEST_F(ProgramTest, UniformMatrixFunctions) {
char infoLog[1024] = ""; char infoLog[1024] = "";
@@ -81,6 +81,28 @@ void main() {
EXPECT_EQ(source.find("#define"), String::npos); EXPECT_EQ(source.find("#define"), String::npos);
} }
TEST_F(ProgramUtilTest, PreprocessFragmentShaderInjectsDepthRangeShim) {
using namespace MG_Util::ShaderTranspiler;
String source = R"(#version 460 core
out float depth;
void main() {
depth = gl_DepthRange.diff * 0.5 + gl_DepthRange.near;
})";
PreprocessShaderSource(ShaderStage::Fragment, source);
EXPECT_NE(source.find("struct mg_DepthRangeParameters"), String::npos);
EXPECT_NE(source.find("#define gl_DepthRange mg_DepthRange"), String::npos);
ShaderAttrib attrib{.shaderType = GL_FRAGMENT_SHADER, .sourceStr = source};
auto res = ShaderCompiler::CompileShader(attrib);
if (!res) {
FAIL() << "errc: " << res.error().errc << "\nlog: " << res.error().log << "\nsource:\n" << source;
}
}
const char* vs = R"(#version 150 const char* vs = R"(#version 150
in vec4 Position; in vec4 Position;
+341 -4
View File
@@ -14,9 +14,52 @@
#include <string> #include <string>
#include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h> #include <MG_Backend/DirectGLES/BackendObject_DirectGLES.h>
#include <MG_Backend/DirectGLES/Managers.h>
#include <MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h>
#include <MG_Backend/BackendObjects.h>
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
#include <MG_Impl/GLImpl/RenderState/GL_RenderState.h>
#include <MG_State/GLState/Core.h>
#include <MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h>
#include <MG_Backend/DirectVulkan/Renderer/VkTextureManager.h>
#include <MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h>
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
#include <MG_Util/ShaderTranspiler/ShaderSourceProcessor.h>
#include <MG_Util/Debug/Log.h> #include <MG_Util/Debug/Log.h>
namespace { namespace {
class DynamicParameterBackend final : public MobileGL::MG_Backend::BackendObject {
public:
explicit DynamicParameterBackend(MobileGL::MG_Backend::DynamicBackendParameters params):
m_params(params) {}
void Initialize() override {}
MobileGL::Bool InitCapabilities() override { return true; }
MobileGL::Bool InitWindowSurface() override { return true; }
const MobileGL::RendererInfo& GetRendererInfo() const override { return m_info; }
MobileGL::String GetBackendAPIVersionString() const override { return "test"; }
const MobileGL::MG_Backend::GlobalBackendFunctionsTable& GetBackendFunctions() const override {
return m_functions;
}
const MobileGL::MG_Backend::DynamicBackendParameters& GetDynamicParameters() const override {
return m_params;
}
MobileGL::BackendType GetBackendType() const override { return MobileGL::BackendType::Unknown; }
private:
MobileGL::MG_Backend::DynamicBackendParameters m_params;
MobileGL::MG_Backend::GlobalBackendFunctionsTable m_functions{};
MobileGL::RendererInfo m_info{
.RendererName = "Test",
.BackendName = "DynamicParameterBackend",
.ExtraVendor = MobileGL::Nullopt,
.RendererGLInfo = {.TargetGLVersion = {3, 3, 0},
.TargetGLSLVersion = {4, 6, 0},
.Extensions = {},
.IsCompatibilityProfile = false},
.StaticBackendCapability = {.AllowVSOnlyPrograms = false}};
};
void SetEnvVar(const char* name, const char* value) { void SetEnvVar(const char* name, const char* value) {
#if defined(_WIN32) #if defined(_WIN32)
_putenv_s(name, value); _putenv_s(name, value);
@@ -48,6 +91,298 @@ TEST(DirectGLESSanity, AdvertisesDepthTextureForGlmarkShadowScenes) {
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end()); EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_depth_texture), extensions.end());
} }
TEST(DirectGLESSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
const auto& extensions = rendererInfo.Extensions;
EXPECT_EQ(rendererInfo.TargetGLVersion.Major, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Minor, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Patch, 0);
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_compute_shader),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_storage_buffer_object),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_direct_state_access),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_multi_draw_indirect),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_indirect_parameters),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_draw_parameters),
extensions.end());
EXPECT_EQ(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_gpu_shader_int64),
extensions.end());
EXPECT_EQ(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_KHR_shader_subgroup),
extensions.end());
}
TEST(DirectGLESSanity, ProvidesNamedFramebufferBlitForDirectStateAccess) {
MobileGL::MG_Backend::DirectGLES::BackendObject_DirectGLES backend;
const auto& funcs = backend.GetBackendFunctions().GL;
EXPECT_NE(funcs.ClearNamedFramebufferfv, nullptr);
EXPECT_NE(funcs.ClearNamedFramebufferfi, nullptr);
EXPECT_NE(funcs.BlitFramebuffer, nullptr);
EXPECT_NE(funcs.BlitNamedFramebuffer, nullptr);
}
TEST(DirectGLESSanity, RewritesBaseInstanceBuiltinForEsslVertexShaders) {
const MobileGL::String source = R"(#version 320 es
void main() {
uint drawId = gl_BaseInstance;
uint untouched = my_gl_BaseInstance_value;
}
)";
const auto rewritten = MobileGL::MG_Backend::DirectGLES::EmulateBaseInstanceInVertexShader(
source, GL_VERTEX_SHADER);
EXPECT_NE(rewritten.find("uniform highp int mg_BaseInstance;"), MobileGL::String::npos);
EXPECT_NE(rewritten.find("uint drawId = mg_BaseInstance;"), MobileGL::String::npos);
EXPECT_NE(rewritten.find("my_gl_BaseInstance_value"), MobileGL::String::npos);
EXPECT_EQ(rewritten.find("uint drawId = gl_BaseInstance;"), MobileGL::String::npos);
}
TEST(DirectGLESSanity, LeavesBaseInstanceBuiltinAloneOutsideVertexShaders) {
const MobileGL::String source = "#version 320 es\nuint value = gl_BaseInstance;\n";
const auto rewritten = MobileGL::MG_Backend::DirectGLES::EmulateBaseInstanceInVertexShader(
source, GL_FRAGMENT_SHADER);
EXPECT_EQ(rewritten, source);
}
TEST(DirectVulkanSanity, AdvertisesTextureStorageForDirectStateAccess) {
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
const auto& extensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_direct_state_access),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_texture_storage), extensions.end());
}
TEST(DirectVulkanSanity, AdvertisesVoxyRequiredRenderingExtensionsWithoutRaisingGLVersion) {
MobileGL::MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
const auto& rendererInfo = backend.GetRendererInfo().RendererGLInfo;
const auto& extensions = rendererInfo.Extensions;
EXPECT_EQ(rendererInfo.TargetGLVersion.Major, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Minor, 3);
EXPECT_EQ(rendererInfo.TargetGLVersion.Patch, 0);
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_compute_shader),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_storage_buffer_object),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_multi_draw_indirect),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_indirect_parameters),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_shader_draw_parameters),
extensions.end());
EXPECT_NE(std::find(extensions.begin(), extensions.end(), MobileGL::E_GL_ARB_gpu_shader_int64),
extensions.end());
}
TEST(DirectVulkanSanity, AdvertisesSubgroupOnlyWhenVulkanReportsUsableSupport) {
using namespace MobileGL;
MG_Backend::DirectVulkan::BackendObject_DirectVulkan backend;
MG_External::VulkanCapabilities unsupportedCaps;
unsupportedCaps.SupportsShaderSubgroup = false;
unsupportedCaps.SubgroupSize = 32;
unsupportedCaps.SubgroupSupportedStages = VK_SHADER_STAGE_COMPUTE_BIT;
unsupportedCaps.SubgroupSupportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT;
backend.ApplyVulkanCapabilitiesForTesting(unsupportedCaps);
const auto& unsupportedExtensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
EXPECT_EQ(std::find(unsupportedExtensions.begin(), unsupportedExtensions.end(), E_GL_KHR_shader_subgroup),
unsupportedExtensions.end());
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSize, 0u);
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedStages, 0u);
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedFeatures, 0u);
MG_External::VulkanCapabilities supportedCaps;
supportedCaps.SupportsShaderSubgroup = true;
supportedCaps.SubgroupSize = 32;
supportedCaps.SubgroupSupportedStages = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
supportedCaps.SubgroupSupportedOperations =
VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_ARITHMETIC_BIT | VK_SUBGROUP_FEATURE_QUAD_BIT;
supportedCaps.SubgroupQuadOperationsInAllStages = true;
backend.ApplyVulkanCapabilitiesForTesting(supportedCaps);
const auto& supportedExtensions = backend.GetRendererInfo().RendererGLInfo.Extensions;
EXPECT_NE(std::find(supportedExtensions.begin(), supportedExtensions.end(), E_GL_KHR_shader_subgroup),
supportedExtensions.end());
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSize, 32u);
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedStages,
static_cast<Uint32>(GL_FRAGMENT_SHADER_BIT | GL_COMPUTE_SHADER_BIT));
EXPECT_EQ(backend.GetDynamicParameters().SubgroupSupportedFeatures,
static_cast<Uint32>(GL_SUBGROUP_FEATURE_BASIC_BIT_KHR |
GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR |
GL_SUBGROUP_FEATURE_QUAD_BIT_KHR));
EXPECT_TRUE(backend.GetDynamicParameters().SubgroupQuadOperationsInAllStages);
}
TEST(DirectVulkanSanity, KeepsOptionalGpuShaderInt64BranchForVoxyQuadDecode) {
using namespace MobileGL;
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectVulkan::BackendObject_DirectVulkan>();
String source = R"(#version 460 core
#extension GL_ARB_gpu_shader_int64 : enable
#ifdef GL_ARB_gpu_shader_int64
uint getLowBits(uint64_t v) {
return uint(v & uint64_t(0xffu));
}
#else
#error int64 branch should be enabled for DirectVulkan
#endif
void main() {
gl_Position = vec4(float(getLowBits(uint64_t(0x2au))));
}
)";
MG_Util::ShaderTranspiler::PreprocessShaderSource(ShaderStage::Vertex, source);
EXPECT_NE(source.find("#extension GL_ARB_gpu_shader_int64"), String::npos);
EXPECT_NE(source.find("GL_ARB_gpu_shader_int64"), String::npos);
auto shaderResult = MG_Util::ShaderTranspiler::ShaderCompiler::CompileShader({
.shaderType = GL_VERTEX_SHADER,
.sourceStr = source,
.flags = MG_Util::ShaderTranspiler::ShaderCompileBits::CompileForOpenGL,
});
EXPECT_TRUE(shaderResult) << (shaderResult ? "" : shaderResult.error().log);
MG_Backend::pActiveBackendObject.reset();
}
TEST(GetterSanity, ReportsKhrSubgroupDynamicParameters) {
using namespace MobileGL;
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
MG_Backend::DynamicBackendParameters params;
params.SubgroupSize = 32;
params.SubgroupSupportedStages = GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT | GL_COMPUTE_SHADER_BIT;
params.SubgroupSupportedFeatures = GL_SUBGROUP_FEATURE_BASIC_BIT_KHR |
GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR |
GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR |
GL_SUBGROUP_FEATURE_QUAD_BIT_KHR;
params.SubgroupQuadOperationsInAllStages = true;
MG_Backend::pActiveBackendObject = MakeUnique<DynamicParameterBackend>(params);
GLint intValue = 0;
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SIZE_KHR, &intValue);
EXPECT_EQ(intValue, 32);
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SUPPORTED_STAGES_KHR, &intValue);
EXPECT_EQ(intValue, static_cast<GLint>(params.SubgroupSupportedStages));
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_SUPPORTED_FEATURES_KHR, &intValue);
EXPECT_EQ(intValue, static_cast<GLint>(params.SubgroupSupportedFeatures));
MG_Impl::GLImpl::GetIntegerv(GL_SUBGROUP_QUAD_ALL_STAGES_KHR, &intValue);
EXPECT_EQ(intValue, GL_TRUE);
GLint64 int64Value = 0;
MG_Impl::GLImpl::GetInteger64v(GL_SUBGROUP_SUPPORTED_FEATURES_KHR, &int64Value);
EXPECT_EQ(int64Value, static_cast<GLint64>(params.SubgroupSupportedFeatures));
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
MG_Backend::pActiveBackendObject.reset();
MG_State::pGLContext.reset();
}
TEST(DirectVulkanSanity, CommandMemoryBarrierMakesIndirectDrawCommandsVisible) {
using namespace MobileGL;
using namespace MobileGL::MG_Backend::DirectVulkan;
const VkMemoryBarrier commandBarrier =
VulkanRenderer::BuildMemoryBarrierForGlBarriers(GL_COMMAND_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
EXPECT_NE(commandBarrier.dstAccessMask & VK_ACCESS_INDIRECT_COMMAND_READ_BIT, 0u);
const VkMemoryBarrier storageOnlyBarrier =
VulkanRenderer::BuildMemoryBarrierForGlBarriers(GL_SHADER_STORAGE_BARRIER_BIT);
EXPECT_EQ(storageOnlyBarrier.dstAccessMask & VK_ACCESS_INDIRECT_COMMAND_READ_BIT, 0u);
}
TEST(DirectVulkanSanity, DrawIndexedIndirectCommandMatchesGlAndVulkanLayout) {
using namespace MobileGL::MG_Backend::DirectVulkan;
EXPECT_EQ(sizeof(DrawIndexedCmdParam), 20u);
EXPECT_EQ(offsetof(DrawIndexedCmdParam, indexCount), 0u);
EXPECT_EQ(offsetof(DrawIndexedCmdParam, instanceCount), 4u);
EXPECT_EQ(offsetof(DrawIndexedCmdParam, firstIndex), 8u);
EXPECT_EQ(offsetof(DrawIndexedCmdParam, vertexOffset), 12u);
EXPECT_EQ(offsetof(DrawIndexedCmdParam, firstInstance), 16u);
}
TEST(DirectVulkanSanity, UndefinedDepthStencilLayoutUsesDontCareForUnclearedAspects) {
using namespace MobileGL;
using namespace MobileGL::MG_Backend::DirectVulkan;
auto noClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, false, false);
EXPECT_EQ(noClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(noClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(noClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
auto depthOnlyClear = ResolveDepthStencilAttachmentLoadInfo(VK_IMAGE_LAYOUT_UNDEFINED, true, false);
EXPECT_EQ(depthOnlyClear.depthLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
EXPECT_EQ(depthOnlyClear.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EXPECT_EQ(depthOnlyClear.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
auto knownLayout = ResolveDepthStencilAttachmentLoadInfo(
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, false);
EXPECT_EQ(knownLayout.depthLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
EXPECT_EQ(knownLayout.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
EXPECT_EQ(knownLayout.initialLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
TEST(DirectVulkanSanity, SampledDepthStencilViewUsesSingleDepthAspect) {
using namespace MobileGL::MG_Backend::DirectVulkan;
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_COLOR_BIT),
VK_IMAGE_ASPECT_COLOR_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_DEPTH_BIT),
VK_IMAGE_ASPECT_DEPTH_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(VK_IMAGE_ASPECT_STENCIL_BIT),
VK_IMAGE_ASPECT_STENCIL_BIT);
EXPECT_EQ(VkTextureManager::ResolveSampledImageViewAspectMask(
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT),
VK_IMAGE_ASPECT_DEPTH_BIT);
}
TEST(RenderStateSanity, ProvokingVertexUpdatesStateAndValidatesEnum) {
using namespace MobileGL;
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
MG_Backend::pActiveBackendObject = MakeUnique<MG_Backend::DirectGLES::BackendObject_DirectGLES>();
GLint mode = 0;
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_LAST_VERTEX_CONVENTION);
const Uint initialVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
EXPECT_GT(MG_State::pGLContext->GetRenderStateParametersVersion(), initialVersion);
const Uint updatedVersion = MG_State::pGLContext->GetRenderStateParametersVersion();
MG_Impl::GLImpl::ProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
EXPECT_EQ(MG_State::pGLContext->GetRenderStateParametersVersion(), updatedVersion);
MG_Impl::GLImpl::ProvokingVertex(GL_TRIANGLES);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_ENUM);
MG_Impl::GLImpl::GetIntegerv(GL_PROVOKING_VERTEX, &mode);
EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION);
MG_Backend::pActiveBackendObject.reset();
MG_State::pGLContext.reset();
}
TEST(LogSanity, UsesEnvOverrideForFilePath) { TEST(LogSanity, UsesEnvOverrideForFilePath) {
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -62,11 +397,13 @@ TEST(LogSanity, UsesEnvOverrideForFilePath) {
MobileGL::MG_Util::Debug::Close(); MobileGL::MG_Util::Debug::Close();
UnsetEnvVar("MOBILEGL_LOG_FILE_PATH"); UnsetEnvVar("MOBILEGL_LOG_FILE_PATH");
std::ifstream logFile(logPath); {
ASSERT_TRUE(logFile.good()); std::ifstream logFile(logPath);
ASSERT_TRUE(logFile.good());
const std::string contents((std::istreambuf_iterator<char>(logFile)), std::istreambuf_iterator<char>()); const std::string contents((std::istreambuf_iterator<char>(logFile)), std::istreambuf_iterator<char>());
EXPECT_NE(contents.find(message), std::string::npos); EXPECT_NE(contents.find(message), std::string::npos);
}
fs::remove(logPath); fs::remove(logPath);
} }
+20
View File
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.14)
add_executable(
TextureTest
TextureTest.cpp
)
target_include_directories(TextureTest PRIVATE
${MGL_ROOT}/include
${MGL_ROOT}/MobileGL
)
target_link_libraries(
TextureTest PRIVATE
GTest::gtest_main
${LINK_LIBRARIES}
)
include(GoogleTest)
gtest_discover_tests(TextureTest)
+222
View File
@@ -0,0 +1,222 @@
// MobileGL - MobileGL/MG_Test/Texture/TextureTest.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#include <gtest/gtest.h>
#include "Includes.h"
#include "Init.h"
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
#include <MG_Impl/GLImpl/RenderState/GL_RenderState.h>
#include <MG_Impl/GLImpl/Texture/GL_Texture.h>
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/TextureState/TextureObject.h>
#include <MG_Util/Texture/TextureFormatProcessor.h>
using namespace MobileGL;
class TextureTest : public ::testing::Test {
protected:
void SetUp() override { MobileGL::Initialize(); }
};
TEST_F(TextureTest, CreateTexturesCreatesObjectsWithoutBinding) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
EXPECT_NE(texture, 0u);
EXPECT_TRUE(MG_State::pGLContext->ValidateTextureObject(texture));
auto& unit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
EXPECT_EQ(unit.GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(), nullptr);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, TextureStorageAndSubImageModifyNamedObjectOnly) {
GLuint namedTexture = 0;
GLuint boundTexture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &namedTexture);
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
const auto boundObjectBefore =
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
MG_Impl::GLImpl::TextureStorage2D(namedTexture, 2, GL_RGBA8, 2, 2);
const Uint8 pixels[] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16,
};
MG_Impl::GLImpl::TextureSubImage2D(namedTexture, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
const auto namedObject = MG_State::pGLContext->GetTextureObject(namedTexture);
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(namedObject.get());
EXPECT_EQ(mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, 0), IntVec3(2, 2, 1));
EXPECT_EQ(mipmapObject->GetMipmapTexelSize(TextureUploadTarget::Texture2D, 1), IntVec3(1, 1, 1));
EXPECT_TRUE(mipmapObject->IsStorageDirty(TextureUploadTarget::Texture2D, 0));
EXPECT_FALSE(mipmapObject->IsStorageDirty(TextureUploadTarget::Texture2D, 1));
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
boundObjectBefore);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, BoundTexSubImage2DUsesCompactRowsAfterUnpackProcessing) {
GLuint texture = 0;
MG_Impl::GLImpl::GenTextures(1, &texture);
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
const Uint8 initialPixels[2 * 16] = {};
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 5, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, initialPixels);
const Uint8 subImageWithGuard[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9,
101, 102, 103,
10, 11, 12, 13, 14, 15, 16, 17, 18,
201, 202, 203, 204, 205, 206,
};
MG_Impl::GLImpl::PixelStorei(GL_UNPACK_ALIGNMENT, 4);
MG_Impl::GLImpl::TexSubImage2D(GL_TEXTURE_2D, 0, 1, 0, 3, 2, GL_RGB, GL_UNSIGNED_BYTE, subImageWithGuard);
const auto textureObject = MG_State::pGLContext->GetTextureObject(texture);
auto* mipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
const auto* stored = static_cast<const Uint8*>(
mipmapObject->MapMipmapData(TextureUploadTarget::Texture2D, 0));
const Uint8 expected[] = {
0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0,
0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0,
};
for (SizeT i = 0; i < sizeof(expected); ++i) {
EXPECT_EQ(stored[i], expected[i]) << "byte " << i;
}
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, GetTextureImageReadsNamedObjectWithoutBinding) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 1);
const Uint8 pixels[] = {
21, 22, 23, 24,
31, 32, 33, 34,
};
MG_Impl::GLImpl::TextureSubImage2D(texture, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Uint8 output[sizeof(pixels)] = {};
MG_Impl::GLImpl::GetTextureImage(texture, 0, GL_RGBA, GL_UNSIGNED_BYTE, sizeof(output), output);
EXPECT_EQ(std::memcmp(output, pixels, sizeof(pixels)), 0);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, GetTextureSubImageReadsFullNamedLevelWithoutBinding) {
GLuint texture = 0;
GLuint boundTexture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
const auto boundObjectBefore =
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 1);
const Uint8 pixels[] = {
41, 42, 43, 44,
51, 52, 53, 54,
};
MG_Impl::GLImpl::TextureSubImage2D(texture, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
Uint8 output[sizeof(pixels)] = {};
MG_Impl::GLImpl::GetTextureSubImage(texture, 0, 0, 0, 0, 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
sizeof(output), output);
EXPECT_EQ(std::memcmp(output, pixels, sizeof(pixels)), 0);
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
boundObjectBefore);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, GetTextureSubImageRejectsPartialReadbackForNow) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
MG_Impl::GLImpl::TextureStorage2D(texture, 1, GL_RGBA8, 2, 2);
Uint8 output[4] = {};
MG_Impl::GLImpl::GetTextureSubImage(texture, 0, 0, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
sizeof(output), output);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_INVALID_OPERATION);
}
TEST_F(TextureTest, TextureParameteriAndBindTextureUnitAreDirectStateAccess) {
GLuint texture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &texture);
MG_Impl::GLImpl::TextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GLint minFilter = 0;
MG_Impl::GLImpl::GetTextureParameteriv(texture, GL_TEXTURE_MIN_FILTER, &minFilter);
EXPECT_EQ(minFilter, GL_NEAREST);
MG_Impl::GLImpl::BindTextureUnit(3, texture);
EXPECT_EQ(MG_State::pGLContext->GetActiveTextureUnit(), 0);
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(3)
.GetBindingSlot(TextureTarget::Texture2D)
.GetBoundObject()
->GetExternalIndex(),
texture);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, TextureParameterfModifiesNamedObjectWithoutBinding) {
GLuint namedTexture = 0;
GLuint boundTexture = 0;
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &namedTexture);
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_2D, 1, &boundTexture);
MG_Impl::GLImpl::BindTextureUnit(0, boundTexture);
const auto boundObjectBefore =
MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject();
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_TEXTURE_MIN_FILTER, static_cast<GLfloat>(GL_LINEAR));
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_TEXTURE_MAG_FILTER, static_cast<GLfloat>(GL_NEAREST));
MG_Impl::GLImpl::TextureParameterf(namedTexture, GL_DEPTH_STENCIL_TEXTURE_MODE,
static_cast<GLfloat>(GL_DEPTH_COMPONENT));
GLint namedMinFilter = 0;
GLint namedMagFilter = 0;
GLint boundMinFilter = 0;
GLint boundMagFilter = 0;
MG_Impl::GLImpl::GetTextureParameteriv(namedTexture, GL_TEXTURE_MIN_FILTER, &namedMinFilter);
MG_Impl::GLImpl::GetTextureParameteriv(namedTexture, GL_TEXTURE_MAG_FILTER, &namedMagFilter);
MG_Impl::GLImpl::GetTextureParameteriv(boundTexture, GL_TEXTURE_MIN_FILTER, &boundMinFilter);
MG_Impl::GLImpl::GetTextureParameteriv(boundTexture, GL_TEXTURE_MAG_FILTER, &boundMagFilter);
EXPECT_EQ(namedMinFilter, GL_LINEAR);
EXPECT_EQ(namedMagFilter, GL_NEAREST);
EXPECT_EQ(boundMinFilter, GL_NEAREST_MIPMAP_LINEAR);
EXPECT_EQ(boundMagFilter, GL_LINEAR);
EXPECT_EQ(MG_State::pGLContext->GetTextureUnitObject(0).GetBindingSlot(TextureTarget::Texture2D).GetBoundObject(),
boundObjectBefore);
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
}
TEST_F(TextureTest, NormalizeDepth24Stencil8UsesPackedDepthStencilType) {
GLenum internalFormat = 0;
GLenum format = 0;
GLenum type = 0;
MG_Util::TextureFormatProcessor::NormalizePixelFormat(GL_DEPTH24_STENCIL8,
PixelFormatNormalizeOptionBit::None,
&internalFormat, &format, &type);
EXPECT_EQ(internalFormat, GL_DEPTH24_STENCIL8);
EXPECT_EQ(format, GL_DEPTH_STENCIL);
EXPECT_EQ(type, GL_UNSIGNED_INT_24_8);
}
@@ -272,6 +272,102 @@ TEST_F(GeneralVertexArrayTest, General_VAOLifecycle) {
EXPECT_EQ(GetError(), GL_NO_ERROR); EXPECT_EQ(GetError(), GL_NO_ERROR);
} }
TEST_F(GeneralVertexArrayTest, General_CreateVertexArraysCreatesObjectsWithoutChangingBinding) {
GLuint bound = CreateVAO();
auto boundObj = MG_State::pGLContext->GetBoundVertexArray();
ASSERT_NE(boundObj, nullptr);
GLuint vaos[2] = {};
CreateVertexArrays(2, vaos);
EXPECT_NE(vaos[0], 0u);
EXPECT_NE(vaos[1], 0u);
EXPECT_NE(vaos[0], vaos[1]);
EXPECT_EQ(IsVertexArray(vaos[0]), GL_TRUE);
EXPECT_EQ(IsVertexArray(vaos[1]), GL_TRUE);
EXPECT_EQ(MG_State::pGLContext->GetBoundVertexArray(), boundObj);
DeleteVertexArrays(2, vaos);
DeleteVertexArrays(1, &bound);
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralVertexArrayTest, General_CreateVertexArraysRejectsNegativeCount) {
GLuint vao = 0;
CreateVertexArrays(-1, &vao);
EXPECT_EQ(GetError(), GL_INVALID_VALUE);
}
TEST_F(GeneralVertexArrayTest, General_DirectStateAccessConfiguresNamedVAOWithoutChangingBinding) {
GLuint bound = CreateVAO();
auto boundObj = MG_State::pGLContext->GetBoundVertexArray();
ASSERT_NE(boundObj, nullptr);
GLuint vao = 0;
CreateVertexArrays(1, &vao);
GLuint vertexBuffer = 0;
GLuint indexBuffer = 0;
CreateBuffers(1, &vertexBuffer);
CreateBuffers(1, &indexBuffer);
NamedBufferData(vertexBuffer, 256, nullptr, GL_STATIC_DRAW);
NamedBufferData(indexBuffer, 128, nullptr, GL_STATIC_DRAW);
VertexArrayVertexBuffer(vao, 2, vertexBuffer, 16, 24);
VertexArrayAttribFormat(vao, 2, 3, GL_FLOAT, GL_TRUE, 12);
EnableVertexArrayAttrib(vao, 2);
VertexArrayElementBuffer(vao, indexBuffer);
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
ASSERT_NE(vaoObj, nullptr);
const auto& attr = vaoObj->GetAttribute(2);
EXPECT_TRUE(attr.Enabled);
EXPECT_EQ(attr.Size, 3);
EXPECT_EQ(attr.Type, DataType::Float32);
EXPECT_TRUE(attr.Normalized);
EXPECT_FALSE(attr.IsInteger);
EXPECT_EQ(attr.Stride, 24);
EXPECT_EQ(attr.Offset, 12);
EXPECT_EQ(attr.Buffer, MG_State::pGLContext->GetBufferObject(vertexBuffer));
EXPECT_EQ(vaoObj->GetIndexBufferBindingSlot().GetBoundObject(), MG_State::pGLContext->GetBufferObject(indexBuffer));
EXPECT_EQ(MG_State::pGLContext->GetBoundVertexArray(), boundObj);
DeleteVertexArrays(1, &vao);
DeleteVertexArrays(1, &bound);
GLuint buffers[] = {vertexBuffer, indexBuffer};
DeleteBuffers(2, buffers);
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralVertexArrayTest, General_DirectStateAccessIntegerAttribAndUnbindElementBuffer) {
GLuint vao = 0;
GLuint indexBuffer = 0;
CreateVertexArrays(1, &vao);
CreateBuffers(1, &indexBuffer);
VertexArrayAttribIFormat(vao, 1, 4, GL_UNSIGNED_INT, 8);
EnableVertexArrayAttrib(vao, 1);
VertexArrayElementBuffer(vao, indexBuffer);
VertexArrayElementBuffer(vao, 0);
auto vaoObj = MG_State::pGLContext->GetVertexArrayObject(vao);
ASSERT_NE(vaoObj, nullptr);
const auto& attr = vaoObj->GetAttribute(1);
EXPECT_TRUE(attr.Enabled);
EXPECT_EQ(attr.Size, 4);
EXPECT_EQ(attr.Type, DataType::Uint32);
EXPECT_TRUE(attr.IsInteger);
EXPECT_FALSE(attr.Normalized);
EXPECT_EQ(attr.Offset, 8);
EXPECT_EQ(vaoObj->GetIndexBufferBindingSlot().GetBoundObject(), nullptr);
DeleteVertexArrays(1, &vao);
DeleteBuffers(1, &indexBuffer);
EXPECT_EQ(GetError(), GL_NO_ERROR);
}
TEST_F(GeneralVertexArrayTest, General_VertexAttributeConfiguration) { TEST_F(GeneralVertexArrayTest, General_VertexAttributeConfiguration) {
GLuint vao = CreateVAO(); GLuint vao = CreateVAO();
GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 128); GLuint vbo = CreateVBO(GL_ARRAY_BUFFER, 128);
@@ -8,6 +8,9 @@
#include "Loader.h" #include "Loader.h"
#include <cstdlib>
#include <cstring>
namespace MobileGL::MG_Util::BackendLoader { namespace MobileGL::MG_Util::BackendLoader {
namespace { namespace {
struct VulkanDynamicFunctions { struct VulkanDynamicFunctions {
@@ -56,6 +59,14 @@ namespace MobileGL::MG_Util::BackendLoader {
return loaded; return loaded;
} }
Bool IsShaderSubgroupForcedDisabled() {
const char* value = std::getenv("MOBILEGL_DISABLE_SUBGROUP");
if (!value) {
return false;
}
return std::strcmp(value, "true") == 0 || std::strcmp(value, "TRUE") == 0;
}
} // namespace } // namespace
inline Version DecodeApiVersion(uint32_t version) { inline Version DecodeApiVersion(uint32_t version) {
@@ -69,6 +80,12 @@ namespace MobileGL::MG_Util::BackendLoader {
return oss.str(); return oss.str();
} }
inline Bool HasUsableShaderSubgroupSupport(const VkPhysicalDeviceSubgroupProperties& subgroupProps) {
return subgroupProps.subgroupSize > 0 &&
(subgroupProps.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0 &&
(subgroupProps.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
}
Bool QueryVulkanCapabilities(MobileGL::MG_External::VulkanCapabilities& caps, VkInstance instance, Bool QueryVulkanCapabilities(MobileGL::MG_External::VulkanCapabilities& caps, VkInstance instance,
VkPhysicalDevice physicalDevice) { VkPhysicalDevice physicalDevice) {
if (!physicalDevice) { if (!physicalDevice) {
@@ -92,8 +109,12 @@ namespace MobileGL::MG_Util::BackendLoader {
return false; return false;
} }
VkPhysicalDeviceSubgroupProperties subgroupProps{};
subgroupProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
VkPhysicalDeviceProperties2 props2{}; VkPhysicalDeviceProperties2 props2{};
props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
props2.pNext = &subgroupProps;
if (vk.vkGetPhysicalDeviceProperties2) { if (vk.vkGetPhysicalDeviceProperties2) {
vk.vkGetPhysicalDeviceProperties2(physicalDevice, &props2); vk.vkGetPhysicalDeviceProperties2(physicalDevice, &props2);
} else { } else {
@@ -157,6 +178,29 @@ namespace MobileGL::MG_Util::BackendLoader {
VkPhysicalDeviceFeatures supportedFeatures{}; VkPhysicalDeviceFeatures supportedFeatures{};
vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures); vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures);
caps.SupportsWideLines = supportedFeatures.wideLines == VK_TRUE; caps.SupportsWideLines = supportedFeatures.wideLines == VK_TRUE;
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(p.limits.maxStorageBufferRange);
const Bool supportsShaderSubgroup = vk.vkGetPhysicalDeviceProperties2 &&
HasUsableShaderSubgroupSupport(subgroupProps);
const Bool forceDisableShaderSubgroup = IsShaderSubgroupForcedDisabled();
caps.SupportsShaderSubgroup = supportsShaderSubgroup && !forceDisableShaderSubgroup;
if (caps.SupportsShaderSubgroup) {
caps.SubgroupSize = subgroupProps.subgroupSize;
caps.SubgroupSupportedStages = subgroupProps.supportedStages;
caps.SubgroupSupportedOperations = subgroupProps.supportedOperations;
caps.SubgroupQuadOperationsInAllStages = subgroupProps.quadOperationsInAllStages == VK_TRUE;
} else {
caps.SubgroupSize = 0;
caps.SubgroupSupportedStages = 0;
caps.SubgroupSupportedOperations = 0;
caps.SubgroupQuadOperationsInAllStages = false;
}
MGLOG_I("Vulkan shader subgroup support: detected=%s advertised=%s size=%u stages=0x%x operations=0x%x",
supportsShaderSubgroup ? "true" : "false", caps.SupportsShaderSubgroup ? "true" : "false",
subgroupProps.subgroupSize, subgroupProps.supportedStages, subgroupProps.supportedOperations);
if (supportsShaderSubgroup && forceDisableShaderSubgroup) {
MGLOG_W("Vulkan shader subgroup support forced off by MOBILEGL_DISABLE_SUBGROUP");
}
return true; return true;
} }
@@ -215,5 +259,11 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.ViewportBoundsRangeMax = properties.limits.viewportBoundsRange[1]; caps.ViewportBoundsRangeMax = properties.limits.viewportBoundsRange[1];
caps.ViewportSubpixelBits = static_cast<Int>(properties.limits.viewportSubPixelBits); caps.ViewportSubpixelBits = static_cast<Int>(properties.limits.viewportSubPixelBits);
caps.SupportsWideLines = false; caps.SupportsWideLines = false;
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(properties.limits.maxStorageBufferRange);
caps.SupportsShaderSubgroup = false;
caps.SubgroupSize = 0;
caps.SubgroupSupportedStages = 0;
caps.SubgroupSupportedOperations = 0;
caps.SubgroupQuadOperationsInAllStages = false;
} }
} // namespace MobileGL::MG_Util::BackendLoader } // namespace MobileGL::MG_Util::BackendLoader
@@ -64,6 +64,12 @@ namespace MobileGL {
Float ViewportBoundsRangeMax = 0.0f; Float ViewportBoundsRangeMax = 0.0f;
Int ViewportSubpixelBits = 0; Int ViewportSubpixelBits = 0;
Bool SupportsWideLines = false; Bool SupportsWideLines = false;
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
Bool SupportsShaderSubgroup = false;
Uint32 SubgroupSize = 0;
Uint32 SubgroupSupportedStages = 0;
Uint32 SubgroupSupportedOperations = 0;
Bool SubgroupQuadOperationsInAllStages = false;
}; };
} // namespace MG_External } // namespace MG_External
namespace MG_Util::BackendLoader { namespace MG_Util::BackendLoader {
@@ -38,6 +38,8 @@ namespace MobileGL {
return BufferTarget::DispatchIndirect; return BufferTarget::DispatchIndirect;
case GL_DRAW_INDIRECT_BUFFER: case GL_DRAW_INDIRECT_BUFFER:
return BufferTarget::DrawIndirect; return BufferTarget::DrawIndirect;
case GL_PARAMETER_BUFFER_ARB:
return BufferTarget::Parameter;
case GL_SHADER_STORAGE_BUFFER: case GL_SHADER_STORAGE_BUFFER:
return BufferTarget::ShaderStorage; return BufferTarget::ShaderStorage;
case GL_UNKNOWN_MGL: case GL_UNKNOWN_MGL:
@@ -210,6 +210,17 @@ namespace MobileGL {
} }
} }
ProvokingVertexMode ConvertGLEnumToProvokingVertexMode(GLenum v) {
switch (v) {
case GL_FIRST_VERTEX_CONVENTION:
return ProvokingVertexMode::FirstVertex;
case GL_LAST_VERTEX_CONVENTION:
return ProvokingVertexMode::LastVertex;
default:
return ProvokingVertexMode::Unknown;
}
}
CapabilityInput ConvertGLEnumToCapabilityInput(GLenum v) { CapabilityInput ConvertGLEnumToCapabilityInput(GLenum v) {
switch (v) { switch (v) {
case GL_BLEND: case GL_BLEND:
@@ -20,6 +20,7 @@ namespace MobileGL {
PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum value); PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum value);
CullFaceMode ConvertGLEnumToCullFaceMode(GLenum value); CullFaceMode ConvertGLEnumToCullFaceMode(GLenum value);
FrontFaceMode ConvertGLEnumToFrontFaceMode(GLenum value); FrontFaceMode ConvertGLEnumToFrontFaceMode(GLenum value);
ProvokingVertexMode ConvertGLEnumToProvokingVertexMode(GLenum value);
CapabilityInput ConvertGLEnumToCapabilityInput(GLenum value); CapabilityInput ConvertGLEnumToCapabilityInput(GLenum value);
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -38,6 +38,8 @@ namespace MobileGL {
return GL_DISPATCH_INDIRECT_BUFFER; return GL_DISPATCH_INDIRECT_BUFFER;
case BufferTarget::DrawIndirect: case BufferTarget::DrawIndirect:
return GL_DRAW_INDIRECT_BUFFER; return GL_DRAW_INDIRECT_BUFFER;
case BufferTarget::Parameter:
return GL_PARAMETER_BUFFER_ARB;
case BufferTarget::ShaderStorage: case BufferTarget::ShaderStorage:
return GL_SHADER_STORAGE_BUFFER; return GL_SHADER_STORAGE_BUFFER;
case BufferTarget::Unknown: case BufferTarget::Unknown:
@@ -211,6 +211,17 @@ namespace MobileGL {
} }
} }
GLenum ConvertProvokingVertexModeToGLEnum(ProvokingVertexMode v) {
switch (v) {
case ProvokingVertexMode::FirstVertex:
return GL_FIRST_VERTEX_CONVENTION;
case ProvokingVertexMode::LastVertex:
return GL_LAST_VERTEX_CONVENTION;
default:
return GL_UNKNOWN_MGL;
}
}
GLenum ConvertCapabilityInputToGLEnum(CapabilityInput v) { GLenum ConvertCapabilityInputToGLEnum(CapabilityInput v) {
switch (v) { switch (v) {
case CapabilityInput::Blend: case CapabilityInput::Blend:
@@ -20,6 +20,7 @@ namespace MobileGL {
GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam value); GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam value);
GLenum ConvertCullFaceModeToGLEnum(CullFaceMode value); GLenum ConvertCullFaceModeToGLEnum(CullFaceMode value);
GLenum ConvertFrontFaceModeToGLEnum(FrontFaceMode value); GLenum ConvertFrontFaceModeToGLEnum(FrontFaceMode value);
GLenum ConvertProvokingVertexModeToGLEnum(ProvokingVertexMode value);
GLenum ConvertCapabilityInputToGLEnum(CapabilityInput value); GLenum ConvertCapabilityInputToGLEnum(CapabilityInput value);
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -38,6 +38,8 @@ namespace MobileGL {
return "DispatchIndirect"; return "DispatchIndirect";
case BufferTarget::DrawIndirect: case BufferTarget::DrawIndirect:
return "DrawIndirect"; return "DrawIndirect";
case BufferTarget::Parameter:
return "Parameter";
case BufferTarget::ShaderStorage: case BufferTarget::ShaderStorage:
return "ShaderStorage"; return "ShaderStorage";
case BufferTarget::Unknown: case BufferTarget::Unknown:
@@ -193,6 +193,17 @@ namespace MobileGL {
} }
} }
String ConvertProvokingVertexModeToString(ProvokingVertexMode v) {
switch (v) {
case ProvokingVertexMode::FirstVertex:
return "FirstVertex";
case ProvokingVertexMode::LastVertex:
return "LastVertex";
default:
return "Unknown";
}
}
String ConvertCapabilityInputToString(CapabilityInput v) { String ConvertCapabilityInputToString(CapabilityInput v) {
switch (v) { switch (v) {
case CapabilityInput::Blend: case CapabilityInput::Blend:
@@ -19,6 +19,7 @@ namespace MobileGL {
String ConvertPixelStoreParamToString(PixelStoreParam value); String ConvertPixelStoreParamToString(PixelStoreParam value);
String ConvertCullFaceModeToString(CullFaceMode value); String ConvertCullFaceModeToString(CullFaceMode value);
String ConvertFrontFaceModeToString(FrontFaceMode value); String ConvertFrontFaceModeToString(FrontFaceMode value);
String ConvertProvokingVertexModeToString(ProvokingVertexMode value);
String ConvertCapabilityInputToString(CapabilityInput value); String ConvertCapabilityInputToString(CapabilityInput value);
} // namespace MG_Util } // namespace MG_Util
} // namespace MobileGL } // namespace MobileGL
@@ -8,7 +8,9 @@
#include "ShaderSourceProcessor.h" #include "ShaderSourceProcessor.h"
#include <algorithm>
#include <cctype> #include <cctype>
#include <MG_Backend/BackendObjects.h>
namespace { namespace {
using MobileGL::SizeT; using MobileGL::SizeT;
@@ -159,6 +161,106 @@ namespace {
return lineEnd == MobileGL::String::npos ? source.size() : lineEnd + 1; return lineEnd == MobileGL::String::npos ? source.size() : lineEnd + 1;
} }
bool IsExtensionAdvertised(MobileGL::GLExtension extension) {
const auto& activeBackendObject = MobileGL::MG_Backend::pActiveBackendObject;
if (!activeBackendObject) {
return true;
}
const auto& extensions = activeBackendObject->GetRendererInfo().RendererGLInfo.Extensions;
return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();
}
MobileGL::String TrimDirectiveToken(const MobileGL::String& token) {
SizeT start = 0;
while (start < token.size() && std::isspace(static_cast<unsigned char>(token[start]))) {
start++;
}
SizeT end = token.size();
while (end > start && std::isspace(static_cast<unsigned char>(token[end - 1]))) {
end--;
}
return token.substr(start, end - start);
}
void FilterUnsupportedGpuShaderInt64(MobileGL::String& source) {
if (IsExtensionAdvertised(MobileGL::E_GL_ARB_gpu_shader_int64)) {
return;
}
SizeT lineStart = 0;
while (lineStart < source.size()) {
SizeT lineEnd = source.find('\n', lineStart);
const bool hasLineBreak = lineEnd != MobileGL::String::npos;
if (!hasLineBreak) {
lineEnd = source.size();
}
const MobileGL::String line = source.substr(lineStart, lineEnd - lineStart);
SizeT probe = 0;
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
probe++;
}
if (probe < line.size() && line[probe] == '#') {
probe++;
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
probe++;
}
constexpr const char* extensionToken = "extension";
constexpr SizeT extensionLen = 9;
const bool hasExtensionDirective =
probe + extensionLen <= line.size() &&
line.compare(probe, extensionLen, extensionToken) == 0 &&
(probe + extensionLen == line.size() || !IsIdentifierChar(line[probe + extensionLen]));
if (hasExtensionDirective) {
probe += extensionLen;
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
probe++;
}
constexpr const char* int64Extension = "GL_ARB_gpu_shader_int64";
constexpr SizeT int64ExtensionLen = 23;
const bool hasInt64Extension =
probe + int64ExtensionLen <= line.size() &&
line.compare(probe, int64ExtensionLen, int64Extension) == 0 &&
(probe + int64ExtensionLen == line.size() ||
!IsIdentifierChar(line[probe + int64ExtensionLen]));
if (hasInt64Extension) {
probe += int64ExtensionLen;
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
probe++;
}
if (probe < line.size() && line[probe] == ':') {
probe++;
const MobileGL::String behavior = TrimDirectiveToken(line.substr(probe));
const SizeT replaceLen = lineEnd - lineStart + (hasLineBreak ? 1 : 0);
if (behavior == "require") {
const MobileGL::String replacement =
"#error GL_ARB_gpu_shader_int64 is not advertised by MobileGL\n";
source.replace(lineStart, replaceLen, replacement);
lineStart += replacement.size();
} else if (behavior == "enable" || behavior == "warn") {
source.replace(lineStart, replaceLen, "\n");
lineStart++;
} else {
lineStart = lineEnd + (hasLineBreak ? 1 : 0);
}
continue;
}
}
}
}
lineStart = lineEnd + (hasLineBreak ? 1 : 0);
}
ReplaceIdentifier(source, "GL_ARB_gpu_shader_int64", "MG_DISABLED_GL_ARB_gpu_shader_int64");
}
void ModernizeLegacyGLSL(MobileGL::ShaderStage stage, MobileGL::String& source) { void ModernizeLegacyGLSL(MobileGL::ShaderStage stage, MobileGL::String& source) {
RemoveDefineForIdentifier(source, "HIGHP_OR_DEFAULT"); RemoveDefineForIdentifier(source, "HIGHP_OR_DEFAULT");
RemoveDefineForIdentifier(source, "MEDIUMP_OR_DEFAULT"); RemoveDefineForIdentifier(source, "MEDIUMP_OR_DEFAULT");
@@ -190,6 +292,18 @@ namespace {
} }
} }
} }
void InjectDepthRangeBuiltinShim(MobileGL::ShaderStage stage, MobileGL::String& source) {
if (stage != MobileGL::ShaderStage::Fragment) return;
if (source.find("gl_DepthRange") == MobileGL::String::npos) return;
if (source.find("mg_DepthRangeParameters") != MobileGL::String::npos) return;
constexpr const char* shim =
"struct mg_DepthRangeParameters { float near; float far; float diff; };\n"
"const mg_DepthRangeParameters mg_DepthRange = mg_DepthRangeParameters(0.0, 1.0, 1.0);\n"
"#define gl_DepthRange mg_DepthRange\n";
source.insert(FindAfterVersionDirective(source), shim);
}
} // namespace } // namespace
namespace MobileGL { namespace MobileGL {
@@ -270,12 +384,15 @@ namespace MobileGL {
} }
} }
FilterUnsupportedGpuShaderInt64(source);
// Some shader packs define helpers with built-in GLSL names such as round(), tanh(), or fma(). // Some shader packs define helpers with built-in GLSL names such as round(), tanh(), or fma().
// These may pass OpenGL-style validation but fail when recompiled for Vulkan/SPIR-V generation. // These may pass OpenGL-style validation but fail when recompiled for Vulkan/SPIR-V generation.
RenameBuiltinShadowingFunction(source, "round", "mg_round"); RenameBuiltinShadowingFunction(source, "round", "mg_round");
RenameBuiltinShadowingFunction(source, "tanh", "mg_tanh"); RenameBuiltinShadowingFunction(source, "tanh", "mg_tanh");
RenameBuiltinShadowingFunction(source, "fma", "mg_fma"); RenameBuiltinShadowingFunction(source, "fma", "mg_fma");
ModernizeLegacyGLSL(stage, source); ModernizeLegacyGLSL(stage, source);
InjectDepthRangeBuiltinShim(stage, source);
} }
} // namespace ShaderTranspiler } // namespace ShaderTranspiler
@@ -342,9 +342,12 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
*outType = GL_UNSIGNED_INT_24_8; *outType = GL_UNSIGNED_INT_24_8;
break; break;
case GL_DEPTH32F_STENCIL8: case GL_DEPTH32F_STENCIL8:
case GL_DEPTH_STENCIL:
*outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; *outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
break; break;
case GL_DEPTH24_STENCIL8:
case GL_DEPTH_STENCIL:
*outType = GL_UNSIGNED_INT_24_8;
break;
default: default:
MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s", MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s",